| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
How do you know your password comparison is actually constant-time?
Measure it.
AI-assisted ("vibe") coding has made this class of bug far more common. LLMs reliably write auth comparisons that work and pass tests, but aren't constant-time — if candidate == secret is the first thing most models reach for unless explicitly told otherwise. If your login endpoint was written with Claude/Copilot/Cursor and never had a dedicated security review, there's a good chance nobody has checked this.
sidecheck is a CLI tool that audits your own HTTP endpoints for remote timing side-channels — the class of bug where comparing a secret with == lets an attacker recover it character-by-character by measuring response time instead of brute-forcing the whole thing.
It's built as a measuring instrument, not an exploit: it tells you whether a measurable timing channel exists and how confident it is, not "here is your password."
flowchart TD
A[secret] --> B[generate requests<br/>wrong value vs correct value]
B --> C[randomize order<br/>interleaved blocks]
C --> D[measure latency<br/>real HTTP round trips]
D --> E[bootstrap resampling]
E --> F[confidence interval]
F --> G[report<br/>significant leak, or clean result]
Network jitter is orders of magnitude larger than the signal you're trying to detect, so naive mean/median analysis doesn't work. sidecheck uses the box-test methodology from Crosby, Wallach & Riedi (ACM TISSEC, 2009) instead — full reasoning and formulas in docs/methodology.md and docs/statistics.md.
sidecheck check https://myapp.local/login \
--header X-API-Key \
--secret "my-real-api-key-do-not-share"──────────────────────────────────────────────── sidecheck timing report ──────────────────────────────────────────────── target https://myapp.local/login field header X-API-Key samples/class 12480 network jitter 1.80 ms ⚠ timing leak detected estimated leak 31.4 μs bootstrap confidence 95.0% (of the measured difference being non-zero) this endpoint responds measurably differently depending on input correctness. an attacker can exploit this to recover secrets character-by-character instead of brute-forcing them. fix: use a constant-time comparison instead of == on secret bytes (e.g. the `subtle` crate in Rust, `crypto/subtle` in Go, `hmac.compare_digest` in Python). ──────────────────────────────────────────────── sidecheck cannot prove the absence of a timing leak — only detect a statistically significant one under the tested conditions. A clean result here is not a safety guarantee. generated by sidecheck 0.2.1 · seed 4891023741 (rerun with --seed 4891023741 to reproduce request order)
Sample size is picked automatically from a quick pilot run. Works against a header, a query parameter, or a JSON body field:
sidecheck check https://myapp.local/api --header X-API-Key --secret "..."
sidecheck check https://myapp.local/api --query token --secret "..."
sidecheck check https://myapp.local/login --json-field password --secret "..."Most real login endpoints need more than just the field under test — a username/email the backend has to look up before it even reaches the password comparison. --json-body supplies the rest of the body as a template:
sidecheck check https://myapp.local/login \
--json-field password \
--json-body '{"username": "admin"}' \
--secret "..."The same problem shows up with headers and cookies: a CSRF token or session cookie the endpoint requires before it even looks at the value under test. --extra-header sends a static header unchanged on every request:
sidecheck check https://myapp.local/api \
--header X-API-Key --secret "..." \
--extra-header "X-CSRF-Token=xyz" \
--extra-header "Cookie=session=abc123"For secrets you don't want in shell history, --value-a/--value-b advanced mode, CI-friendly --report/--output-csv output, and comparing a run against a baseline to catch regressions specifically (sidecheck compare), see docs/usage.md and docs/reproducibility.md.
cargo install --locked sidecheck--locked matters: without it, cargo install re-resolves dependencies against whatever is newest on crates.io, which can pull in transitive crates requiring a newer Rust edition than your installed toolchain supports. --locked uses the Cargo.lock committed in this repo, which is known to build. MSRV is rust-version = "1.85" — update via rustup if your system Cargo predates that (some LTS distros ship an older one by default).
# build from source instead
cargo build --release
./target/release/sidecheck check --helpsidecheck doctor is a measurement feasibility estimator, not just a diagnostic ping. It answers "is this network path even capable of resolving a leak of a realistic size" before you spend minutes to hours on a full check — the same question check asks itself from its pilot batch, surfaced up front so you can decide before committing to a specific field or secret.
sidecheck doctor https://myapp.local/login────────────────────────────────────────────────
sidecheck doctor
────────────────────────────────────────────────
target https://myapp.local/login
samples 300
median RTT: 8.2 ms
RTT jitter: 0.42 ms (low)
packet loss: 0.0%
recommended samples: ~2765881 (to reliably detect a ~1μs leak, the
rough scale of a real == vs constant-time bug)
environment quality: GOOD
────────────────────────────────────────────────
this path looks suitable for timing measurement. proceed with `sidecheck check`.
The recommended sample count can look enormous even on a "GOOD" path — GOOD means the estimate itself is trustworthy, not that the run will be fast. A ~1μs leak is genuinely hard to see behind 0.42ms of jitter; check will refuse to run past --max-samples (default 200,000) in a case like this unless you pass --force. See docs/statistics.md for the exact formula behind the recommendation.
For CI: a composite Action wraps the binary and can fail a PR only on a new leak relative to a baseline, not any pre-existing one.
- uses: casablanque-code/sidecheck/action@v0.2.1
with:
target-url: https://preview.example.com/login
header: X-API-Key
secret: ${{ secrets.SIDECHECK_TEST_KEY }}See action/README.md for the full input/output reference and action/examples/pr-gate.yml for a complete baseline-comparison workflow.
sidecheck cannot prove the absence of a timing leak. A clean result means no statistically significant difference was found under the tested conditions — not that the endpoint is safe. Treat a positive result as strong evidence of a bug; treat a negative result as "nothing found here," not a certificate of safety.
Two more limits worth knowing before you trust a result: sidecheck has no way to tell whether your injection point actually reached the code path you meant to test (see --json-body/--extra-header above and docs/limitations.md), and a genuine leak on a short secret is often not reliably detectable over real HTTP at all — the network noise floor can exceed a nanosecond-scale CPU leak entirely. Full details, plus current project status, in docs/limitations.md.
MIT
| Back | FazBrowse Home | New Git URL |