Sneak a secret message inside a string
Hide secrets inside innocent-looking strings.
Hide the name of a platform inside your username. If you receive unsolicited email mentioning you by name, you might find out where the person found your info.
This will help you find who's leaking your personal information to spammers/hackers/recruiters...
There are two modes of operation in sneacret.
From this post.
The mode zws is a variation of the technique described in the post.
From this post.
The mode vs is a variation of the technique described in the post.
deno install \
--global \
--no-prompt \
--allow-read \
--allow-env \
--allow-exec=wl-copy \
jsr:@quilicicf/sneacret- Global installation to use it from anywhere
- No prompt to avoid being pestered by Deno's permission system
- Allow read & env because the CLI building tool (yargs) requires access to CWD & env variables
- Allow exec to allow sneacret to use your platform's clipboard tool to copy the results of your commands. See clipboard.ts for more info.
To hide secret inside the string Container:
sneacret hide \
--container 'Container' \
--secret 'secret' \
--to-clipboardArguments:
--mode (-m): the mode to use.zwsorvs(default)--container (-c): the string in which to hide the secret--secret (-s): the secret to hide--to-clipboard (-t): copies the result to the clipboard, see underlying OS tools in clipboard.ts
Reveal the secret hidden inside a string
To reveal the secret hidden inside Container:
sneacret show \
--mode "zws" \
--container "Container"Arguments:
--mode (-m): the mode to use.zwsorvs(default)--container (-c): the string that contains the secret to reveal--to-clipboard (-t): copies the result to the clipboard, see underlying OS tools in clipboard.ts
To show all the supported characters, use:
sneacret alphabet \
--mode "zws"Arguments:
--mode (-m): the mode to use.zwsorvs(default)
stringWithSecret="$(sneacret hide -c Container -s Secret)"
# Displaying the result in the terminal might not work.
# Depending on the font, some invisible characters might get truncated.
# Pipe it to your clipboard or a file to avoid issues, the parameter --to-clipboard is there for this reason.
sneacret show -c "$stringWithSecret"There are 6 invisible characters that I identified, 5 of which seem to be supported correctly by most websites (see SPACES_MAP in zws-encoder.ts).
I could have encoded the utf-8 character code of each character in my secret in binary like it's done in the article, but I figured I'd try to be more efficient.
For my use-case, being able to hide characters from the alphabet and a few punctuation marks is enough. This means that I have ~30 characters to encode.
Given the number of invisible characters I'm using, I can encode all my alphabet in just 3 slots because: 5^3 > 125.
This means that if I create an alphabet where all letter are numbered from 0 to 25, I can express them in a base-6 number where 0 === String.fromCharCode(0x200B), 1 === String.fromCharCode(0x200C) etc. for all my characters.
Concrete example:
Name=Quilici
Secret=github
SecretAsCharacterCodes=6,8,19,7,20,1
SecretAsCodeInBase6=10,12,31,11,32,01
SecretAsZwsCharacterCodes=0x200B,0x2060,0x200C,0x200B,0x2060,0x2060,0x200C,0x200B,0xFEFF,0x200B,0x2060,0x200D,0x200C,0x200C,0x200B,0x200B,0x200D,0x200C
EncodedSecret='Quilici' # yes there are 12 invisible spaces there!This mode is fully straightforward. The number of characters in the variation selectors list is 256. That's way more than what I need to encode simple information in the form [a-zA-Z0-9-_.]+ which size is 26+26+10+3=65.
This means I can allocate one variation selector for each character in my secret.
Concrete example :
Name=Quilici
Secret=LinkedIn
SecretAsCharacterCodes=47,18,23,20,14,13,44,23
SecretAsVsCharacterCodes=0xe011f,0xe0102,0xe0107,0xe0104,0xfe0e,0xfe0d,0xe011c,0xe0107
EncodedSecret=Q󠄟󠄂󠄇󠄄︎︍󠄜󠄇uilici # yes there are 8 variation selectors there!The characters may not visible, but they will still change some behaviors
- In some sites, if not supported by the font they'll show as squares
- In some sites they'll be swallowed for multiple possible reasons
- Because the invisible characters are still characters
- The double click selects a word, it will select only the part that's not cut by invisible spaces (only in
zwsmode) - Your usual keyboard shortcut to select/move word by word will act the same, it'll get stuck on the invisible spaces
- Moving the caret through the word will be a pain as it'll have to go through each character
- The double click selects a word, it will select only the part that's not cut by invisible spaces (only in
- Wrapping may decide to cut your word in two
- Your name may exceed limits on the platform because the spaces count as characters of course
- If used in the service provided by the platform, it may cause horrible bugs