Repository navigation
Sightread FAQ
Answers to common questions, fixes for common problems and the honest limits of Sightread. If yours isn't here, check the CLI reference or open an issue (see the end of this page).
These are the limits Sightread states in its README, its help and every report. Read them before you rely on a clean result.
-
Sightread never runs the code it downloads.
--soundcheckis the one exception: it installs the update on a staging copy and loads it in a browser, so the new code runs there. - No risk signals found means Sightread found no known risk signal in what it could analyse. It is evidence for your review, not a guarantee that the update is safe. It can miss obfuscation it cannot decode, logic that waits for a date or a domain, code fetched at run time from a server that serves clean code to scanners, compiled assets and binaries and changes in a dependency of the package that Sightread did not review.
- Unanalysed means a file was too large or too strange to read. It fails the gate by default because hiding code that way is a known trick.
- "Verified" means something different for each source, and never "verified as safe". npm: matches the hash and signature the npm registry publishes. WordPress.org plugins: matches WordPress.org's own checksums (both come from WordPress.org, so this proves the copy was not changed on the way, not what the author intended). Themes: downloaded over TLS from WordPress.org; WordPress.org publishes no theme checksums. Composer: pinned to a commit; Packagist publishes no archive hash for most packages. See Sources and integrity.
- A registry signature or provenance proves who published and from which workflow, not that the content is harmless. A worm that publishes from a hijacked CI can carry valid provenance.
- Owner change detection depends on what the registry shows. WordPress.org shows contributors and committers, not sales; a transfer that keeps the same account is invisible.
- Typosquat checks compare names with a list of popular packages; a niche package can be squatted without a match.
- Each lookup tells that registry a package name and version you use, and reports hold your full inventory. Private names stay local. See Security model.
- A staging copy made by Roadie is pseudonymised, not anonymised. Echo's seal stops mail, SMS and webhooks, not every outbound connection.
- A signed report proves it was not changed after signing and which key signed it. A local key proves only "this machine".
-
WordPress can install updates on its own (auto-updates, forced security releases). A gate only covers updates you run by hand or through your tooling. With
--wp, Sightread warns when plugin auto-updates are on. - Sightread reports what changed. It does not judge intent. Every report ends with that line.
They know published advisories: a version someone already reported. The updates that hurt most arrive as a normal, signed release with no advisory yet: a plugin bought and backdoored, a hijacked npm account, a typosquatted dependency. Sightread reads the update itself and says what it adds. It also asks OSV for known records (known-malicious, known-vulnerable), so it's never weaker than an audit for npm and Composer. Dependabot and Renovate open the pull request; Sightread reviews it (see CI).
Tuner checks what a site exposes now: leaks, known vulnerabilities, weak config. Sightread reads what an update will change before you install it. They meet at "update available": Tuner says a plugin is vulnerable and an update is out, Sightread reads that update. --from-tuner tuner.json reads the installed versions from a Tuner report.
Sightread compares what the two versions can do. A signal fires only when a capability is in the new version and absent from the installed one. In one real Laravel vendor tree unserialize( appears in 28 packages and eval( in 11; flagging presence would flag almost every update. To review what you already run, use --to installed --from <older version>, or all --rereview across a site.
Yes for reviews: Sightread reads the site's files (or a --wp listing) and never changes them. With --wp, it runs only plugin list, theme list, core version and option get auto_update_plugins. --soundcheck installs updates, so it refuses a production site; see With Soundcheck and Roadie.
There is no official source to check a premium plugin against, so a plugin with its own Update URI, or whose files match nothing on WordPress.org, is listed under Not checked as not-wporg and never sent to WordPress.org. Give the vendor's zip with --to-file (and the installed one with --from-file if you have it); the update is reviewed and marked UNVERIFIED. See Sources and integrity.
Out of scope in 1.0. Core is listed under Not checked (WordPress core is out of scope in v1, hint WordPress core updates come signed from WordPress.org) but it's informational: it never makes a run partial or fails --fail-on. Must-use plugins and drop-ins are listed the same way.
Sightread couldn't establish where its bytes came from: a local file (--to-file, --from-file, an installed premium plugin), WordPress.org checksums that were unavailable, or an archive that hit a limit. It isn't diffed, so you see no findings. It also makes the run incomplete. --allow-unverified reviews it anyway and keeps the UNVERIFIED verdict. Under --fail-on, an unverified update exits 3 unless --allow-unverified.
Something wasn't checked: a package Not checked (premium, private, a git dependency), a fetch that failed or an update that couldn't be verified. The verdict box says what and the JSON has complete: false. Without --fail-on the run still exits 0; with it, exit 3 unless --allow-partial (gaps) or --allow-unverified (unverified updates).
The finding's confidence is likely: the detector matched a shape that is usually what it says, not an exact pattern. --min-confidence confirmed keeps likely findings out of the verdict and the gate (they stay in the JSON with below_confidence: true).
A context rule raised the finding one level. A new owner makes new code more suspicious, so code signals in the same update go up one level; two code signals in one function raise the lower one. See Context rules.
--severity, --id and --exclude-id hide findings from the report only. Hidden findings still set the verdict and still count for --fail-on. The report says so: note: 4 findings are hidden by --severity critical (they still count for the verdict and --fail-on). To stop a finding counting, add an ignore entry to the config, an allow entry or a baseline.
The installed version is the candidate. Use --to <version> to review another one, --to list to see them, or --to installed --from <older> to review what you run against the release before it.
The lockfile isn't at the base ref, for example a new lockfile or a wrong --base: <lockfile> is not at <base>, so every package in it counts as added. Check --base and that the checkout has history (fetch-depth: 0 in Actions).
The source didn't give Sightread what it needs to verify the bytes, so the update wasn't diffed. Run again later, or --allow-unverified to review it anyway (the report marks it unverified).
Composer packages hosted on GitHub and npm tag checks call api.github.com, which allows 60 requests an hour without a token. Sightread plans its requests before it starts, so this comes before the allowance is spent. Set GITHUB_TOKEN (sent only to api.github.com). In GitHub Actions the Action passes the job's token.
The registry rate-limited Sightread and still did after the retries. Run again in a few minutes, or lower --jobs.
With --offline (or RHYTHM_OFFLINE set) only cached data and archives are used and some weren't cached. Run once without it to fill the cache. Every offline run says so in its report: Offline: only cached data and archives were used.
composer and npm compare versions a lockfile pins. Run your package manager once to write one, or point --path at the folder that has it. bun.lockb is Bun's binary lockfile, which Sightread can't read: bun install --save-text-lockfile writes bun.lock.
Install them with rhythm install soundcheck roadie, or pass --skip-roadie-verify (the report says the staging copy wasn't checked). See With Soundcheck and Roadie.
report, explain and allow --from read the JSON a review wrote. A file that was edited, cut short or written in another format is refused:
$ rhythm sightread report before.json b04.json -o merged.md -o merged.sarif
rhythm sightread: b04.json is not valid JSON (invalid character 't' after top-level value)
give the JSON a review wrote, such as -o sightread.json
The config is checked before anything is fetched. Unknown keys name the nearest valid one; see Configuration.
rhythm sightread doctor checks what a review needs: each source answers, the npm registry's signing keys match the set pinned in the build, the cache is writable, GITHUB_TOKEN, git and, when the config has a soundcheck section, rhythm-soundcheck and rhythm-roadie. Here it ran against the testbed's mirrors on 127.0.0.1, so the sources are named by their mirror addresses:
$ rhythm sightread doctor
✓ Config .sightread/config.yaml
✓ Cache .../.cache/rhythm/sightread is writable
✓ 127.0.0.1:18900 answers (127.0.0.1 answered 404)
...
✓ 127.0.0.1:18903 answers (127.0.0.1 answered 404)
✓ 127.0.0.1:18904 answers (127.0.0.1 answered 404)
✓ npm keys 1 key of 127.0.0.1 matches the set pinned in this build
✓ GitHub token not set; the mirror at 127.0.0.1 reports 4999 of 5000 requests left this hour
✓ git /usr/bin/git
✓ Signal data sightread-names 2026.10.26, sightread-signals 2026.10.26
14 checks passed, 0 failed.
The GitHub API here is the testbed's mirror, which sets its own limits. Against api.github.com without a token the line is a warning instead: ! GitHub token not set, so 57 of 60 requests left this hour; set GITHUB_TOKEN for Composer packages and tag checks.
--offline skips the network checks:
$ rhythm sightread doctor --offline
ok Config: .sightread/config.yaml
ok Cache: .../.cache/rhythm/sightread is writable
skip Sources: offline
warn GitHub token: not set: api.github.com allows 60 requests an hour without one
ok git: /usr/bin/git
ok Signal data: sightread-names 2026.10.26, sightread-signals 2026.10.26
4 checks passed, 0 failed.
A failed npm keys check (<host> serves <n> signing keys this build does not pin) means the registry rotated its keys: update Sightread. Exit 1 when a check fails.
Open an issue at https://github.com/RhythmShahriar/sightread/issues with the command you ran, the output with -v and rhythm sightread version. Check the output for private package names and paths before you paste it. A false alarm or a miss on a real package is worth an issue: name the package and the two versions.
Found a security problem in Sightread itself? Don't open a public issue. Report it privately at https://github.com/RhythmShahriar/sightread/security/advisories/new. See the Security policy.
← CLI reference · Home · Benchmark →
rhythm · Useful ideas. Working systems. · Check only sites you own or have permission to test. Keep staging sealed (responsible use) · This wiki is published from wiki/ in the rhythm repository; suggest changes there with a pull request.
Get started
rhythm in depth
Tuner
- Overview
- Your first scan
- Reading results
- Choosing checks
- Requests and politeness
- Output and reports
- Batch scans
- Local scans
- Integrity and malware
- Changes and notifications
Tuner in depth
- Known vulnerabilities
- PHP advisories
- CI and code scanning
- GitHub Action
- Config file
- Watch and serve
- Writing checks
- Check packs
- Finding reference
- CLI reference
- Coming from Wordfence CLI or WPScan
- FAQ and troubleshooting
Soundcheck
- Overview
- Your first check
- Reading results
- Review and accept
- Discovery
- Page health
- Visual changes
- Interactions
- Forms and flows
- Cache
- Speed
- Accessibility and SEO
- EAA mode
- Keyboard walkthrough
- Accessibility statement
Soundcheck in depth
- CI
- CI baselines and PR comments
- Configuration
- Error rules and exec
- WordPress updates
- Fleet and client reports
- History
- Import from BackstopJS and Lost Pixel
- Firefox and WebKit
- CLI reference
- FAQ and troubleshooting
- Benchmark
Echo
- Overview
- Your first run
- Connectors
- Sealing staging
- Echo Inbox
- Messages and checks
- Checks and rules
- Attachments
- Actions and compare
- With Soundcheck
- Replay
- Deliverability
Echo cookie consent
Echo in depth
- Docker and DDEV
- Agency hub and reports
- Schedule
- MCP server
- Conformance kit
- CI
- Configuration
- API
- CLI reference
- FAQ and troubleshooting
- Benchmark
Roadie
- Overview
- Getting started
- Copy and prepare
- Sources and targets
- Profiles
- Pseudonymisation
- Live keys
- Kill switch
- Verify and reports
Roadie in depth
- Laravel
- Generic SQL and Postgres
- Multisite
- CI and the GitHub Action
- Configuration
- Security and limits
- CLI reference
- Troubleshooting
- FAQ and honest limits
- Benchmark
Sightread
- Overview
- Your first review
- Signal reference
- Allow and baseline
- Sources and integrity
- With Soundcheck and Roadie
- Watch
Sightread in depth
- CI and the GitHub Action
- Configuration
- Output and reports
- Security model
- CLI reference
- FAQ and honest limits
- Benchmark
Project