When a browser navigates through Rammerhead, the destination URL appears in the address bar, browser history, and server access logs. URL shuffling replaces the readable URL with an opaque encoded form that is meaningless without the session’s private dictionary. The encoding is applied per-character and is position-dependent, so the same URL looks different in every session.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/binary-person/rammerhead/llms.txt
Use this file to discover all available pages before exploring further.
Why URL shuffling exists
Without shuffling, any URL you visit through the proxy is visible in plaintext to:- The server’s access log
- Browser history
- Browser extensions that read
location.href - Anyone who can see the address bar
_rhsQ3nR2xBmT9... instead of https://example.com/path. The actual destination is only recoverable by someone who knows the session’s shuffleDict — a 64-character randomly ordered string generated at session creation time.
The base dictionary
Only characters that are safe to embed in a URL path without percent-encoding are eligible for shuffling. The set is derived from printable ASCII (U+0020–U+007E), minus/, _, and any character that would be percent-encoded by encodeURI:
baseDictionary — including spaces, Unicode, and most punctuation — is passed through the shuffler unchanged.
Generating a per-session dictionary
At session creation,StrShuffler.generateDictionary() produces a random permutation of baseDictionary:
baseDictionary appears exactly once, in a random order. This dictionary is stored as session.shuffleDict and is included when the session is serialized to disk.
The shuffle algorithm
StrShuffler takes the session dictionary in its constructor. The shuffle method encodes a URL string:
- Find its index (
idx) inbaseDictionary. - Add the character’s position (
i) to create position-dependence. - Wrap around with modulo (64) and look up the result in the session’s
dictionary.
The _rhs prefix
Every shuffled string is prefixed with _rhs (the shuffledIndicator):
- Idempotency:
shuffle()checks for the prefix at the start and returns the string unchanged if it is already shuffled. This prevents double-encoding. - Detection:
unshuffle()checks for the prefix to know whether decoding is needed. A string without_rhsis returned as-is.
The unshuffle algorithm
unshuffle is the exact inverse:
idx - i) undoes the addition from shuffle. The mod helper uses the positive-modulo formula ((n % m) + m) % m to keep the result in range when the subtraction goes negative.
Percent-encoded characters
Any%XX sequence is passed through both shuffle and unshuffle without modification. This is critical because percent-encoding is how browsers represent characters that are otherwise illegal in a URL (spaces as %20, etc.). Shuffling these sequences would produce an invalid URL.
str.length - i >= 3 ensures a bare % at the end of a string (not part of a valid %XX triplet) is still passed through rather than causing an index error.
Enabling and disabling shuffling per session
Shuffling is enabled by default when a session is created (shuffleDict is set to a random dictionary). You can toggle it via /editsession:
setupRoutes.js:
shuffleDict is null, Rammerhead skips the shuffle/unshuffle step and the destination URL is used as-is in proxy paths.
Does shuffling provide strong security?
Does shuffling provide strong security?
Shuffling is an obfuscation mechanism, not encryption. It hides URLs from casual inspection in logs and browser history, but it is not designed to withstand a determined attacker who has access to the session dictionary. For network-level privacy, run Rammerhead over HTTPS.
Why is position factored into the encoding?
Why is position factored into the encoding?
Without position-dependence, the mapping from source character to encoded character would be fixed across the entire URL. An attacker who saw many shuffled URLs from the same session could perform frequency analysis to recover the dictionary. Position-dependence ensures each character position has an independent substitution, defeating simple frequency attacks.
Can two sessions produce the same shuffled output for the same URL?
Can two sessions produce the same shuffled output for the same URL?
Extremely unlikely. Each session’s dictionary is an independent random permutation of 64 characters (64! ≈ 1.27 × 10^89 possible dictionaries). The probability of two sessions sharing an identical dictionary is negligible.
Sessions
How sessions store the shuffleDict and other per-user state
JavaScript caching
How Rammerhead caches rewritten JS to reduce CPU load