Skip to main content
Myrqen is local-first. The scan, the findings, the secrets, and the reports live on your machine. The hosted service exists to make a report visible to other people, and it only ever receives what the sync contract explicitly allows.

The pieces

Who supplies the reasoning

The host agent does. Myrqen never holds a model provider credential and never asks for one — ADR 001 records that decision. What Myrqen supplies is everything around the reasoning:
  • the methodology and the phase structure,
  • the authorization and safety gates the agent must pass through,
  • the finding contract, identity, deduplication, and redaction,
  • the report, in four formats,
  • and, if asked, the cloud collaboration layer.

The two halves of a scan

1

Myrqen's static pass

session start parses the project and follows attacker-controlled data through a function — including the shapes real code uses: destructured request reads, values accumulated into an array and joined, aliases, type assertions — and records where that data reaches a sink with nothing in between. It runs whether or not an agent is involved, which is what makes the engine measurable against a corpus.
2

The agent's dynamic validation

Static reading cannot observe a response. Every static candidate is therefore a claim, and the agent settles it against the running application: finding verify raises it to verified, finding refute records that it could not be reproduced and keeps the finding labelled. An unsettled candidate stays needs_review and the report says so.

Trust boundaries

These are the lines the implementation is built around. The full set is in docs/02-architecture/TRUST-BOUNDARIES.md.
Repository files, .env values, cookies, tokens, test credentials, raw traffic, and local database contents stay local. What may reach the cloud is report prose, explicitly selected evidence, redacted secret references (a label, a kind, and a local HMAC fingerprint — never the value), and the metadata the sync contract names. The full repository is never uploaded; policy.uploadFullRepository is false in every session context.
Application pages, API responses, source comments, issue text, dependency metadata, and logs are untrusted. They cannot grant scope, authorize a target, change policy, or redirect a tool. An attempt is recorded as a finding, and the scan continues under the original policy.
The CLI holds a revocable device credential scoped to API operations. The browser holds a session cookie. The device-link approval URL carries an opaque request id and never a durable bearer token.
Analytics events are an allowlisted schema with no generic properties path. Report text is never copied into an analytics row to enrich it.
Share filtering happens on the server. Nothing a viewer may not see is present in their HTML, their JSON, or their export. Client-side visibility is never the security boundary.
Administrators see operational metadata by role. Reaching a customer’s report body requires a separate, expiring support grant with a written reason, a password re-entry, and an audit trail — and every use is counted.
Clients verify an ed25519 signature against a pinned public key, check the artifact digest and size, and refuse downgrades, stale manifests, and revoked versions before anything is written to disk. A compromised API response cannot become code execution.

Data at rest in the hosted service

Report bodies are encrypted with REPORT_ENCRYPTION_KEY before they reach object storage, so the store never holds plaintext. REPORT_ENCRYPTION_KEY_PREVIOUS accepts retired keys for reads only, which is what makes rotation possible without orphaning every stored report. Live progress is fanned out over PostgreSQL LISTEN/NOTIFY by default, which works across replicas; a single-process memory driver exists for development.

Scan lifecycle

The eight phases and the states a scan moves through.

Authorization and safety

Scope classes, the prohibited list, and injection quarantine.