Skip to content

Repository files navigation

Hearsay

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.

The two tools that already do part of this

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.

The files nobody scans

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 Windows half

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.

It never prints a secret

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.

What it says about you when there is no secret at all

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.

And who else can already read it

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.

Running it

hearsay
hearsay --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.

A gap is not a pass

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.

It only reads

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.

Building

Needs Go and nothing else. No dependencies at all.

go build -o hearsay .
go test ./...

Licence

MIT. Do what you like with it.

About

The forty files on your machine that write down what you type, not just the shell history: the password in your mysql CREATE USER, whatever you last copied in vim, every line you have ever run in IPython. It never prints a secret.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages