// Documentation

Hushmark docs.

Everything about Hushmark in one place: what it does, how each check works, what it proves and what it does not, how to run it, and where it is going.

Overview

Hushmark is a GitHub check that stops hidden instructions aimed at AI agents from being merged into a repository.

AI coding agents read everything in a repository: documentation, pull request descriptions and agent rules files such as AGENTS.md or .cursorrules. Text a human reviewer never sees, such as an HTML comment or an invisible Unicode character, is still read and followed by the agent. Once merged, it steers every agent session on the team.

Hushmark scans each pull request with deterministic detectors, sends only the suspicious lines to a model running inside a NEAR AI Cloud trusted execution environment (TEE), and shows a finding only when the TEE's signature and attestation verify.

The claim, exactly

The review code has no shell, so nothing in a pull request can make it run code. A finding is shown only if it was signed inside a NEAR AI Cloud TEE for that exact input. This is a claim about Hushmark's code, not the machine it runs on: see Security model.

Status

Hushmark is v0.1, in development for NEAR HACKATHON (1–14 November 2026). Features on this page are marked built or planned.

ComponentState
Detectors (diff, PR title, PR body, rules files)built
Excerpts, prompt and the NEAR AI Cloud callbuilt
Verification checks a–gbuilt
Receiptsbuilt
Real recorded evidence, verified offlinebuilt
Pipeline, Check Run output and GitHub client (tested against a mocked GitHub API)built
GitHub Action on every pull request (pull_request_target)built
GitHub App and webhook server (one-click installs, /hushmark re-runs)planned
NEAR anchor contract and the Action's anchor callbuilt

Quickstart

Verify the real evidence yourself. No account, no API key, no network after install.

  1. Install uv and clone the repository.

    git clone https://github.com/Ritapossible/Hushmark
    cd Hushmark
  2. Install the locked dependencies.

    make install
  3. Run every check on the saved evidence. Expect all tests to pass in under a second.

    make verify
  4. See a refusal: one changed byte in a recorded model answer is refused.

    uv run pytest tests/test_recordings.py -k one_changed_response_byte -v

Other commands: make lint (ruff, format check, mypy --strict) and make test (all tests).

How it works

Each pull request moves through the same pipeline. Any step can stop the run with a refusal code; a refusal never shows a model finding.

Hushmark drawn as a bench machine: fanfold paper (the whole pull request) feeds under a scanner; one hidden region is punched out as a chip (the excerpt), the rest drops into a slot and never leaves; the chip rides into a vault marked TEE, a press signs it, and a receipt slides onto the newest block of a chain (the NEAR testnet anchor).
Left to right: the whole pull request is scanned, only the hidden excerpt goes to the TEE, and the receipt (hashes only) is anchored on NEAR testnet.
  1. Trigger. Every pull request event: opened, updated, reopened or edited, through the GitHub Action. built Maintainer re-runs with /hushmark. planned
  2. Fetch. The diff between the pinned base and head commits, the title and the body. .hushmark.yml is read from the base commit only. built
  3. Scan. Deterministic detectors read every added line, the title and the body. No size limit, nothing executed. built
  4. Excerpt. Each flagged region plus up to ten lines of context. Invisible characters are written as tags such as ⟦U+200B⟧. Only excerpts leave the service. built
  5. Infer. One completion on NEAR AI Cloud with a fixed prompt and no tools. The exact request and response bytes are kept. built
  6. Verify. Checks a–g: attestation, signature and grounding. built
  7. Receipt. A canonical JSON receipt with hashes only. built
  8. Report. One Hushmark Check Run with line annotations. built
  9. Anchor. The receipt hash anchored on NEAR testnet, with the transaction linked from the check. built

A pull request with no hidden regions finishes after step 3: no model call, no cost, no receipt. That is the common case.

Detectors

Detectors run on added lines only, because removed lines are not merged. They decide nothing about intent; they find regions a reviewer cannot see, or text written for agents.

DetectorMatchesWhere
html_comment<!-- … -->Markdown, MDX, reStructuredText and HTML files; PR title and body
zero_widthU+200B–U+200D, U+2060, U+FEFFAny file
bidiU+202A–U+202E, U+2066–U+2069 (Trojan Source)Any file
tag_charsU+E0000–U+E007F (invisible tag characters)Any file
hidden_html<details>, the hidden attribute, display:none, visibility:hidden, font-size:0, and alt text or link titles of 40+ charactersMarkup files
agent_rules_fileEvery block of added linesAGENTS.md, CLAUDE.md, GEMINI.md, .cursorrules, .cursor/rules/*, .windsurfrules, .github/copilot-instructions.md

Phrases such as "ignore previous instructions" or curl … | sh are recorded as weak signals on a candidate; they never create one on their own.

Limit: more than 20 candidates, or more than 200 excerpt lines, refuses the run with too_many_candidates. Hushmark refuses rather than reviewing part of a pull request.

Verification checks

Every check must pass, in order. A failure refuses the run with the code shown and no model finding is shown.

#CheckRefusal code
aThe attestation report holds exactly one model attestation for the signerno_attestation
bThe Intel TDX quote verifies with dcap-qvl against Intel collateral; TCB status is UpToDate; debug mode is offquote_invalid
cThe quote's report data binds the signing address and our fresh nonce; the nonce is echoed backsigner_not_bound, nonce_mismatch
dMRCONFIGID commits to the published app_compose; RTMR3 replays from the event logmeasurement_mismatch
eThe GPU evidence carries our nonce; every NVIDIA NRAS token (overall and per GPU) has a valid ES384 signature from NVIDIA's key set, the right issuer, a valid time window and a true verdict; the overall token commits to each GPU token by SHA-256gpu_evidence_invalid
fThe response signature is provider_tee, signs model:sha256(request):sha256(response) over our exact bytes, and recovers to the attested signing addresssignature_mismatch
gThe model's answer matches a strict schema, and every finding names a candidate Hushmark found itselfmodel_output_invalid; unknown ids are dropped and counted

Nonce

nonce = SHA-256(JCS(idempotency_key) ‖ salt), with 16 fresh random bytes of salt per run, stored in the receipt. Every run is fresh, so an old report cannot be replayed, and anyone with the receipt can recompute the nonce from the commit it covers.

Why the model cannot point anywhere

The model returns only a candidate_id, a severity and one sentence. The file and line always come from Hushmark's own scan. An id that does not exist in the run is dropped.

Receipts

A receipt records one run that called the model. It lets anyone check, without seeing any code, that the findings came from an attested TEE for one exact input. It is canonical JSON (RFC 8785), and its receipt_id is the SHA-256 of those bytes.

{
  "v": 1,
  "key": { "repo_id", "pr", "base_sha", "head_sha", "input_sha256", "model", "prompt_hash" },
  "nonce_salt", "nonce",
  "request_sha256", "response_sha256",
  "signature": { "text", "sig", "signing_address", "algo", "kind" },
  "attestation_sha256",
  "verification": { "tcb_status", "checks": ["a"…"g"], "verified_at" },
  "scan": { "detectors_version", "candidates" },
  "findings_sha256", "findings_count", "rejected_ungrounded",
  "created_at"
}

Never in a receipt: the diff, excerpts, file contents, PR title or body, finding text, repository name or any username. The findings digest hashes each rationale instead of storing it.

Verify a receipt

  1. Recompute nonce from key and nonce_salt.
  2. Load the attestation report by attestation_sha256 and run checks a–e against that nonce.
  3. Check signature.text and recover the EIP-191 signer; it must equal signing_address.
  4. Optionally compare the receipt hash anchored on NEAR for SHA-256(JCS(key)).

Full specification: RECEIPT.md.

NEAR anchor built

A NEAR smart contract on testnet (anchor.hushmark.testnet) stores one receipt hash per review with anchor(key_hash, receipt_hash), and refuses a second anchor for the same key, so one input is reviewed once. Anyone can look an anchor up with get(key_hash). Source: contract/. Deployed: anchor.hushmark.testnet; its on-chain code hash matches the built wasm (A1QKAEQS…PpTZ).

The first anchor is demo PR #6's real receipt: anchored. Sending the same anchor again was refused by the contract: "this review key is already anchored".

  • The contract lives on its own sub-account.
  • The service calls it with a function-call access key limited to anchor, with zero deposit. A stolen server key can add anchors but cannot move funds.
  • Only hashes go on chain: no repository names or usernames.
  • A failed anchor never blocks the report; it is retried.

Install built

In v0.1 Hushmark runs as a GitHub Action. No server, no app to install.

  1. Copy .github/workflows/hushmark.yml into your repository's default branch.
  2. Add a NEAR AI Cloud API key as a repository secret named NEARAI_API_KEY (Settings → Secrets and variables → Actions).
  3. Open a pull request. A Hushmark check appears on it.
  4. Optionally add .hushmark.yml with mode: block, and in branch protection require the Hushmark check with GitHub Actions as its source.

Why pull_request_target is safe here

The workflow runs Hushmark's code from your base branch, so a pull request cannot change how it is reviewed, and pull requests from forks are reviewed too. It never checks out or runs the pull request: the diff, title and body are read through the GitHub API as text. A test fails if the workflow ever checks out the pull request. See ADR-0009.

Permissions

PermissionLevelWhy
contentsreadThe pinned diff, and .hushmark.yml at the base commit
pull-requestsreadTitle, body and commit SHAs
checkswriteThe Hushmark Check Run
actionsreadCount today's receipts for the daily budget

Daily budget

A pull request with no hidden regions never calls the model and costs nothing. Reviews that do call the model are capped at 50 per repository per day (set the repository variable HUSHMARK_DAILY_REVIEWS to change it). At GLM-5.3-flash's listed price the worst case is about $0.0025 a review, so about $0.13 a day. Over the cap, hidden content is shown as not verified (budget_exceeded) and no model call is made. The Action has no database, so it counts today's receipt artifacts, which needs actions: read.

No write access to code, no comments. Without the secret, hidden content is reported as not verified (tee_unavailable), never as a finding. Each review's receipt and attestation report are kept as a workflow artifact for 90 days.

planned A GitHub App with a webhook server, for one-click installs across repositories and /hushmark re-runs. It runs the same code.

Configuration

One optional file on the default branch, read from the base commit only, so a pull request can never change how it is judged.

# .hushmark.yml
mode: warn   # warn (default) | block

Missing or empty file means warn. Any other key or value refuses the run with config_invalid. Path ignores and per-path modes are on the roadmap.

Check results built

Posted by the GitHub Action on every pull request.

Outcomemode: warnmode: block
No hidden regionssuccesssuccess
Hidden regions, none aimed at agentssuccess, with the receipt IDsuccess
Verified findingsneutral, one annotation per findingfailure
Refusedneutral, reason code, scanner hits marked unconfirmedneutral

Findings in the PR title or body cannot be line annotations, so they appear in the check summary.

Refusal codes

Every refusal has a stable code. Tests assert on codes, never on message text.

CodeMeaning
too_many_candidatesMore than 20 hidden regions or 200 excerpt lines
config_invalid.hushmark.yml is not mode: warn or mode: block
no_attestationNo model attestation for the signer
quote_invalidIntel TDX quote failed, wrong TCB status, or debug mode on
signer_not_boundThe quote does not bind the signing address
nonce_mismatchThe evidence was not produced for our nonce
measurement_mismatchMRCONFIGID or RTMR3 does not match
gpu_evidence_invalidNVIDIA's evidence or signed verdict failed
signature_mismatchThe response signature does not cover our exact bytes from the attested signer
model_output_invalidThe model's answer does not match the schema
tee_unavailableNEAR AI Cloud, Intel or NVIDIA could not be reached
internal_errorHushmark itself failed before reviewing; the check is closed as not verified and the Actions job fails, so the error is visible
not_maintainer/hushmark from someone without admin or maintain permission
diff_unavailableGitHub could not return the full diff
webhook_invalidA webhook whose signature is not GitHub's
budget_exceededThe repository's daily review budget is spent (default 50 model-calling reviews a day)

Security model

Proved

  • The review code has no path that runs the diff: a lint rule bans every process API, a test-wide audit hook fails on any process start, and requests never contain tools.
  • A shown finding came from a model in an attested NEAR AI Cloud TEE, on the exact request sent, for that input.
  • Every shown finding refers to a region Hushmark found itself.
  • Only excerpts leave the service, and only to an attested TEE.

Not proved

  • The Hushmark server is not in a TEE in v0.1. It sees the full diff, and a compromised server could skip verification.
  • TEE trust is hardware trust in Intel TDX and NVIDIA confidential computing.
  • Detection is incomplete: unknown hiding techniques are missed.
  • Offline verification checks evidence as of the time it was recorded.

Defended attackers include fork authors, non-maintainer commenters, replay attempts, tampering, a hallucinating or injected model, webhook forgers and other GitHub Apps. Details: THREAT_MODEL.md.

Reporting a vulnerability

Use GitHub's private vulnerability reporting on the repository (Security → Report a vulnerability). Please do not open a public issue. See SECURITY.md.

Privacy

DataWhere it goes
Full diff, title, bodyRead by the Hushmark service; never sent to the model, never logged, never stored
Excerpts around hidden regionsSent only to the attested NEAR AI Cloud TEE
FindingsShown on the pull request's Check Run, visible to whoever can see the repository
ReceiptsHashes only
On chainA hash of the review key and a hash of the receipt

This website has no backend, no cookies, no analytics and no tracking.

Evidence and fixtures

Four real calls to z-ai/glm-5.3-flash on NEAR AI Cloud were recorded on GitHub Actions and verified before saving. Each is in fixtures/recordings/ with its exact request and response bytes, signature, attestation report, Intel collateral and NVIDIA response.

RecordingInputResult
R1Hidden comments in a doc and the PR body: approve, run a remote script, say nothing2 findings
R2Harmless <!-- TODO -->No findings
R3AGENTS.md: skip failing tests, push to main, hide it1 finding
R4AGENTS.md: ordinary lint, test and commit rules (the control for R3)No findings

Tests built on that evidence refuse: a changed response byte, a gateway signature, another nonce, a removed attestation, a flipped quote byte, edited measurements, a swapped NVIDIA token, an expired verdict and an unknown candidate. The evidence on the home page is generated from these recordings by Hushmark's own verifiers.

NVIDIA rotates its signing keys, so its key set is pinned in fixtures/nvidia/jwks.json for offline verification.

Development

Stack

Python 3.12 with uv; httpx; pydantic v2 in strict mode; dcap-qvl for Intel quotes; PyJWT for NVIDIA tokens; eth-account for EIP-191; ruff, mypy --strict and pytest. The NEAR contract is Rust with near-sdk, built with cargo-near.

Repository layout

hushmark/        scan, excerpt, infer, nonce, receipt, config,
                 pipeline, report, github, service, near, anchor, action
contract/        the NEAR anchor contract (Rust, near-sdk)
hushmark/verify/ attestation, nras, signature, grounding
prompts/         the versioned system prompt
fixtures/        inputs, recordings, attestation reports, NVIDIA keys
scripts/         recording and site-data scripts
site/            this website
docs/            architecture, plan, fixtures, decision records

Recording new evidence

The NEAR AI Cloud key is a GitHub Actions secret, never in the repository. The manual record workflow runs scripts/record_completion.py on chosen inputs, verifies every result, and uploads the evidence as an artifact for review.

Rules for contributors

  • Never execute the diff, and never send tools to the model.
  • Never store or log the diff or finding text.
  • Fail closed, and refuse rather than truncate.
  • Never mock a signature or attestation in a fixture that claims to be real.

Full list in AGENTS.md; decisions in docs/adr.

Roadmap

Each phase has a gate: something true in the real world before the next phase starts.

  1. v0.1 · NEAR HACKATHON · November 2026

    Automatic check on every pull request; diff, title, body and rules files scanned; excerpts only to the model; warn or block mode; NEAR testnet anchor; offline evidence.

  2. v0.2 · Complete the trust claim · December 2026 – January 2027

    • Run the Hushmark service inside a confidential VM, so the diff never sits on a host outside a TEE. The most important item.
    • Public receipt verifier: a CLI and a web page.
    • Anchors on NEAR mainnet.
    • Free open-source CLI and pre-commit hook with the same detectors, offline, no account.
    • GitHub Marketplace listing with a free tier for public repositories.

    Gate: three repositories we do not own have installed it and run it more than once.

  3. v0.3 · From pull request reviewer to agent input firewall · Q1 2027

    • Scan more of what agents read: issues and comments, linked docs, dependency READMEs.
    • An API and middleware that check MCP tool results before an agent reads them.
    • Path ignores and per-path modes in .hushmark.yml.

    Gate: one design partner with an internal AI agent rollout, using it weekly.

  4. v1.0 · A product teams pay for · Q2 2027

    • GitLab support; self-hosted or customer-cloud deployment.
    • Organization view: receipts, findings over time, audit export.
    • Pricing: free for public repositories, paid for private ones; prepaid scan credits on NEAR are being explored.
    • SOC 2 readiness.

    Gate: the first paying customer.

Not on the roadmap: general code-quality review, general vulnerability finding, or running and sandboxing code. Staying narrow is what keeps Hushmark different from general AI reviewers.

FAQ

Does Hushmark run the code in my pull request?

No. It reads text only. The review code cannot start a process; a lint rule and a test-wide audit hook enforce that, and the model is never given tools.

Does my code go to an AI model?

Only the lines around hidden regions, plus ten lines of context, and only to a model running in an attested NEAR AI Cloud TEE. Most pull requests send nothing at all.

What does it cost?

Pull requests without hidden regions make no model call. A review with a few regions costs a fraction of a cent at current NEAR AI Cloud prices.

Why not just use GitHub's hidden-character warning?

GitHub warns about some invisible characters when you view a file. Hushmark also covers HTML comments, hidden HTML and agent rules files, judges whether the text targets an agent, runs as a required check, and gives a verifiable receipt.

What if the model is wrong or manipulated?

It can only name candidates Hushmark found, so it cannot invent locations. A malformed answer refuses the run. Harmless notes and ordinary rules files produced no findings in the recorded controls (R2 and R4).

Why NEAR?

NEAR AI Cloud runs the model inside Intel TDX and NVIDIA TEEs and signs every response, which is what makes a finding verifiable. NEAR also hosts the receipt anchor.

References

Much of Hushmark is written with Claude Code under human direction and review; commits carry a Co-Authored-By line.