What your machine overheard you say.
[WRITTEN] 3 secrets are written down in ~/.mysql_history
line 412 a password in a CREATE USER or ALTER USER
line 908 a password in a CREATE USER or ALTER USER
line 1204 a password in a role or user statement
MYSQL_HISTFILE=/dev/null, and mysql_config_editor with
--login-path instead of typing -p. Run again with --reveal to
see the lines, with the secrets themselves still covered over.
[WRITTEN] 2 secrets are written down in ~/.viminfo
line 214 a setting with a password in it
line 219 a private key
set viminfo='100,<0,s0,h in ~/.vimrc keeps the registers out
of it.
[TELLS ] 61 machines you have reached, 44 of them private
the ones only reachable from inside:
hidden:344a258f
hidden:98670f4d
...
[TELLS ] your timestamps say you are at the keyboard between 09:00 and 01:59
You have thought about .bash_history. Around forty other files on the
same disk are also writing down what you type, and they are the ones still
holding a live password, precisely because nobody defends them.
The mysql client keeps your CREATE USER line. Vim keeps whatever you last
copied. IPython keeps every line you have ever run, in a database that
never rolls over. less keeps everything you have ever searched for inside
a file, which is what you were doing when you were looking for a token.
PowerShell keeps every session in plain text, forever, in a file that is
the first thing anything landing on a Windows box goes and reads.
PassDetective is in Kali and
it works. It opens two files: ~/.bash_history and ~/.zsh_history, both
written into the source by hand, both under $HOME, so on Windows it finds
nothing at all.
shellclear covers four
shells including PowerShell, and it has not been touched since May 2023.
Its answer is also the opposite of this one: clear, stash and restore,
all of which rewrite the file. A tool that edits your history is a tool that
can lose it, and neither of them opens a single one of the files below.
Around forty of them, in a list rather than a search of your disk, because a hit has to be a hit and the report has to be able to say what the file keeps and how to turn it off. A pattern match over a home directory cannot say either.
Database clients, which is where this stops being a shell history
scanner. .mysql_history takes IDENTIFIED BY 'something' exactly as
typed, and MySQL's own manual warns about it. .psql_history is documented
by PostgreSQL, which tells you to use \password for this reason.
.rediscli_history has your AUTH in it because AUTH has no other form.
Then .dbshell, .sqlite_history, .duckdb_history, cqlsh_history, and
the prompt_toolkit trio of pgcli, mycli and litecli.
Language prompts. .python_history is on by default and full of the
API key somebody pasted into requests.get to check it worked.
.ipython/profile_default/history.sqlite is the worst one here: a database
rather than a file, so it never rolls over, holding the output as well as
the input, written to by every Jupyter notebook you have ever run a cell in.
Then node, irb, pry, R, PHP, Julia and gdb.
Editors and pagers. ~/.viminfo holds your registers, which is
whatever you last copied. Copy a password out of a config file in vim to
paste it somewhere and it is written to disk when you quit. .lesshst
holds every search you have run inside a file. Also neovim's shada and
nano's search history.
Windows. ConsoleHost_history.txt, one per host program, so the VS Code
terminal and the console keep separate ones and clearing one leaves the
other alone. Plus Start-Transcript output, which is worse than a history
because the responses are in it too, and the copy in a Documents folder
that OneDrive has taken over.
The ones that are somewhere else by design. Atuin exists to copy your history to a server and to your other machines, so a secret in there is a secret in all of those and deleting the local file undoes none of it. The AWS command line keeps a database of every call and its full response, if somebody ever turned it on to debug something and never turned it back off.
The list above is a Unix shape, because that is the shape this problem was first written up in. Windows writes down what you did somewhere else entirely, and not in a file anybody edits.
A shortcut for every file you have opened. Windows drops one into Recent
every time anything opens anything, and nothing prunes the folder. A .lnk
is a record rather than a link: the whole path, the serial number of the
drive it was on, when it was opened, and in most of them the NetBIOS name of
the machine. They outlive the file, so a document on a memory stick from two
years ago is still on the record along with the stick.
A timeline of every program you have used. Kept in SQLite, with what was open and for how long, and synced to an account when one is signed in. What it holds depends on whether activity history was ever turned on, and the report says which it found rather than assuming.
And the ones it does not read, named rather than skipped. The web cache of Edge, what Recall recorded, the clipboard history, Sticky Notes. Each is a place that holds what somebody typed. A list of forty places that quietly stops at the easy ones is a list that lies about its own coverage.
Not without --reveal, not with it, and there is no flag for it.
Running a scanner that reads your passwords back at you puts them in your scrollback, in whatever you piped the output to, and in the history of the shell you just ran it in. That is a strange way to end a job about secrets in your history.
So the default report gives you the file and the line number and what kind
of thing is on it. --reveal prints the line, with the secret still
covered over, and the marker is a fixed width because one dot per character
would hand over the length. Tests check that nothing out of any file
reaches the output either way.
Every rule names the thing it finds. There is deliberately no "this string
looks random" rule: that is how these tools get their long feature lists and
it turns a report into a page of maybes. And the safe forms stay quiet, so a
bare mysql -p, a --password-stdin or a \password is not reported at
somebody for doing it right.
Take every password out and the file is still a description of a person and their job. This is the half the other two skip.
- The machines you reach, and which of them are on a network somebody has to already be on. An internal name is only useful to somebody who knows the network it belongs to, which makes it a good way of working out which network that is.
- The accounts you log in as, on other people's machines.
- The hours you are awake, out of the timestamps zsh and fish write next to every command. This is the one people are most surprised by: it gives away the timezone you are actually in, whatever your profile says.
- How far back it goes. Shell history is one of the few things on a machine nobody ever cleans, so it usually outlasts the job it was written during.
Is it inside a git repository? Keeping your configuration in git is a
good habit and this is what it costs: one git add . publishes everything
you have typed. Dotfile managers link rather than copy, so this follows the
symlink to find the repository the file actually lives in. If a .gitignore
names it, Hearsay says nothing, because somebody already thought about that
one.
Is it in a folder that syncs? Dropbox, OneDrive, iCloud and the rest. A copy is on their servers and on every other machine on that account.
Can anybody else on this machine read it? And is there a .bak next to
it from the time somebody cleared the original, holding the older and more
interesting version.
hearsayhearsay --reveal--reveal names the machines and prints the lines. It does not reveal
secrets, because nothing does.
Set HEARSAY_HOME to read a different home directory, which is also how
the tests work and how you check a Windows profile from inside WSL.
Exit code is 1 when something is written down, 3 when something could not be read, 0 when nothing turned up.
Windows marks anything that came from the internet, so the first run may bring up a blue "Windows protected your PC" box. Right click the zip, Properties, tick Unblock at the bottom, and then extract it.
Finding nothing is not a clean bill of health and the report says so.
This reads the files it knows about, with rules that each name what they find. A password that does not look like anything in particular, in a file nobody has told it about, is somewhere it never looked. Two files are kept in a database rather than as text, and those are read as loose strings rather than parsed, which means no line numbers and no promise that nothing was missed. The report says that where it happens rather than quietly counting them as clean.
There is no registry reading here, so the Windows Run dialog history is not covered. That would mean a dependency, and it is not worth one.
Nothing is written, nothing is deleted, no socket is opened and no other
program is run. Those are not promises in a readme: tests read the source
and fail the build if a write call, an import of net or an import of
os/exec ever turns up in it.
Needs Go and nothing else. No dependencies at all.
go build -o hearsay .go test ./...MIT. Do what you like with it.