Rules of the method

Updated 2026-11-07 · version 0.1Draft · awaiting review

The method says in plain words what is checked and how to use the result. This page holds the rules behind every published value, version 0.1: what each level of each right means, where the three readings come from, how a lab run is read, how the run advice is derived, which tools get in, and how evidence is written. It is the page to cite when a value is disputed. Both pages share one version number; the changelog lives here.

Inclusion criteria

A candidate becomes an entry (tier 1, “listed”) only if it meets all of these, checked before any text is written:

  1. Security relevance in topics, description or SKILL.md, mappable to at least one value of the task vocabulary.
  2. Open licence with an SPDX identifier. Repositories without a licence are recorded with reason no-license.
  3. Activity: last push within 180 days; not archived.
  4. Form: a manifest exists (SKILL.md, server.json, plugin.json, server.yaml or openai.yaml) and an installation path is documented. Agents (type: agent) rarely ship one of these manifests, and many MCP servers (type: mcp-server) ship only package metadata such as package.json or pyproject.toml; for both, the criterion is met when an installation path is documented and the entry can be pinned to a fixed commit. A release is not required.
  5. Waiting period: the repository is at least 14 days old, so fresh campaigns do not flow straight into the catalog.
  6. Deduplication by canonical GitHub URL plus subpath, registry name, package identifier and SKILL.md hash; forks only if maintained independently.
  7. Static scan passed or with an explained finding. The result is labelled “static-scanned”, never a security verdict.
  8. Plausible reach: a value of 3 on any right needs a sentence of justification, otherwise the candidate is recorded with rights-3-without-justification.

Not included: models and fine-tuned models, closed-source products without clear terms, and tools with a malicious finding (those are reported to the platform or registry; only hash, indicators and a behaviour description are published). Standalone offensive agents are described, pinned and linked, but never distributed through the marketplace.

Candidates not listed. A candidate that misses a criterion is recorded in the repository with its reason, date and evidence (file and line at the commit it was read at), one file per candidate, and is not published. Ask us why a tool is not listed at hello@readbeforerun.ai; the answer names the criterion and its evidence. Maintainers have a grace period of 14 days to fix the reason and can report a fix to the same address.

Privilege Reach

Principles

  1. Absolute anchors instead of task fit. Values are measured against the working directory, the declared target and published lists of sensitive paths and hosts. Whether the reach fits the purpose is the separate judgement fit (fits, partial, excessive). A pentest agent with shell and network honestly lands on 2; that is no flaw.
  2. Three sources, kept apart: Declared (author: manifest, frontmatter, annotations, README), Code (static: code, path and URL literals, scanner output), Lab (one lab run).
  3. Maximum, not average. The level is the highest value; the scale is ordinal.
  4. Unknown is not zero. Without evidence the value is “?” (grey). Server-side behaviour of remote MCP servers stays “?”.
  5. Observation is a lower bound. Lab shows what happened, not what is possible; Lab below Code is normal and does not mean “safer”.
  6. Versioned, script-based, correctable. Every value carries the method reach-v0.x. Every change to a published value (the declared, code or lab level of a right, the pinned commit, the tier) is logged in the entry with date, old and new value and reason and shown on /changes/; a removed or renamed entry is listed there too. The checks refuse a changed value or a removed entry without such a record. A new lab run is listed as a run, not as a change.
  7. Zero never means “safe”. The zero labels are per source: none declared, none found, none observed.

Six rights, four levels

Each right is a row with its question. A value needs one evidence line; without evidence it is “?”.

Right 0 1 2 3
Files (where does it read and write?) reads only the working directory and files passed to it reads outside (home, system files without secrets) or writes only in the working directory writes or deletes outside the working directory or on the target host filesystem mounted, writes to system paths, mass deletion
Network (whom does it talk to?) no network except the client’s model endpoint only the declared target and declared hosts undeclared hosts or arbitrary URLs uploads to undeclared third parties, tunnels, listeners
Execution (what does it run?) starts no processes fixed, declared programs free shell or code execution (shell=True, eval, Bash(*), shell injection in SKILL.md) privilege escalation: sudo, setuid, Docker socket, privileged container
Secrets (which credentials does it touch?) none one scoped token passed by the user for the declared service several or broad tokens, reads environment variables wholesale, or reads secret files inside the working directory (committed .env, keys) reads credential stores (SSH keys, cloud profiles, browser cookies, agent tokens, .env files outside the working directory)
Persistence (what survives the run?) only result files caches or temp files outside changes tool or target configuration, global package install autostart, services, cron, shell rc, new keys or users, agent configuration, installs further skills
Approval (does it ask before acting?) respects approvals, brings no pre-approvals narrow pre-approvals (for example Bash(git status *)) broad pre-approvals (Bash(*), write) or instructions to use auto modes demands or sets a bypass (bypassPermissions, yolo, danger-full-access, sandbox or hooks off)

Short labels shown in each cell of the grid:

Right 0 1 2 3
Files project only reads outside writes outside system paths
Network no network declared hosts any host exfil or tunnel
Execution no processes declared programs shell or eval sudo, docker socket
Secrets none one scoped token broad tokens or env credential stores
Persistence results only cache or temp config or global install autostart, users, keys
Approval asks narrow pre-approvals broad pre-approvals bypasses approval

Level words: 0 contained (reads only what you give it), 1 scoped (its task and its target, nothing beyond), 2 open (writes, executes, reaches the open network), 3 privileged (touches secrets, persistence or admin rights). Red means “run isolated”, not “bad”. A missing declared cell reads “not declared”, an unknown cell “?”.

Where each column comes from

  • Declared comes only from explicit author statements: allowed-tools and disallowed-tools (in Claude Code a pre-approval, not a restriction, so it counts for Approval), MCP tool annotations (readOnlyHint, destructiveHint, openWorldHint; the MCP specification asks to treat them as untrusted, so they count only as Declared), MCPB user_config.sensitive, Docker server.yaml (run.allowHosts, disableNetwork, volumes, user, config.secrets), OpenClaw requires.bins and requires.env, Codex openai.yaml, the OWASP Universal Skill Format, README statements about modes. A missing declaration creates no value at all, not even zero. It is the normal case for skills and itself a finding.
  • Code comes from code, literals and manifests at the pinned commit: path and URL literals, network libraries, process execution, environment access, install scripts, shell injection in SKILL.md, scanner output. A model may propose values; a value is written only with an evidence line that a script has verified against the file. Every mode the code or the repository ships counts, not only the default: an optional HTTP transport that listens on all interfaces raises the network value even when the catalogued stdio install stays local. The code level is the ceiling you sandbox against, so the cautious reading applies; the entry’s notes name the narrower default.
  • Lab comes from the artifacts of the run, separated into install and run phase; the run phase decides the value.

Reading the lab artifacts

The highest matching signal decides. Every value points to a file and line in the run folder.

Observation File Right Value
only the model gateway and internal DNS contacted egress.jsonl Network 0
test target or declared host contacted egress.jsonl Network 1
undeclared host contacted, or a firewall block egress.jsonl, blocked.jsonl Network 2
bytes above the upload threshold to an undeclared host; tunnel, listener egress.jsonl Network 3
nothing written except result paths; reads only in the working directory fs-diff.json, host-events.jsonl Files 0
reads outside the working directory without secrets, or writes only inside it host-events.jsonl, fs-diff.json Files 1
writes or deletes outside the working directory or on the target fs-diff.json Files 2
writes to system paths, mounted host filesystem, mass deletion fs-diff.json, host-events.jsonl Files 3
no execve besides the tool itself host-events.jsonl Execution 0
only programs named in declared.json host-events.jsonl Execution 1
shell, interpreter or undeclared programs host-events.jsonl Execution 2
sudo, setuid, Docker socket, privileged container host-events.jsonl Execution 3
no access to the credential path list, no environment enumeration host-events.jsonl Secrets 0
only the passed token read host-events.jsonl, declared.json Secrets 1
wholesale environment enumeration, several tokens host-events.jsonl Secrets 2
access to credential paths or canaries; canary string in egress host-events.jsonl, egress.jsonl Secrets 3
diff empty except result files fs-diff.json Persistence 0
cache or temp outside survives fs-diff.json Persistence 1
configuration of target or tool changed, global install fs-diff.json Persistence 2
cron, timer, service, authorized_keys, shell rc, new user, agent configuration fs-diff.json, host-events.jsonl Persistence 3
every action without pre-approval produced an event (asked or denied), no pre-approvals brought hitl-events.jsonl Approval 0
pre-approvals only for narrow, declared patterns hitl-events.jsonl, declared.json Approval 1
broad pre-approvals or a request for an auto mode in the recording hitl-events.jsonl, session.txt Approval 2
bypass demanded or set session.txt, configuration diff Approval 3
no events at all (runtime without approval events) none Approval ?

For Approval to be observable at all, the client that drives the tool under test runs in mode dontAsk with an empty allow list, and a lab approver hook answers every tool call: it allows the calls the task names (published with the observation as runtime.allow_list), denies everything else and records each decision. So every action without a pre-approval produces an event, and an approval from the task list is the lab’s answer to a request, not a pre-approval the tool brought. Every run also records scope violations (actions outside the task).

Surplus and the lab verdict

Per right: scope is the declared level where the author declared the right, otherwise level 1, the task scope (the declared target, the passed token, the declared programs, a cache, narrow approvals, reading outside the project without secrets: what a tool may do for its task anyway). surplus = max(0, lab − scope); if the lab value is unknown, the surplus is null.

surplus.count is the number of rights with a surplus above 0. It gives the lab verdict:

Verdict When
not run yet no lab run
as declared surplus 0 on every right, at least one right declared
within task scope surplus 0, nothing declared
beyond declared (N) surplus above 0 on N rights

Behaviour beyond the static analysis (a lab value above a known code value) is listed per run as beyond_static on the observation card, never in the badge. A difference of ordinal levels is never shown as a number.

Run advice (verdict rule v0.1)

Where we have read a tool under the verdict rule (data/verdict/rule.yaml, one file per entry in catalog/<slug>/verdict.yaml), the card opens with one of three words: Run isolated, Restrict first, Keep confirmations on. The word says how to run the tool, not how good or safe it is, and it is derived from the findings and steps of the verdict file, never written by hand:

  1. Run isolated when a finding in the default setup matches one of the five triggers below and no setting closes it, or when a step before first use demands isolation.
  2. Restrict first when the code shows a right of level 2 or 3, or a right is unknown, or the approval gate cannot be determined, and settings contain it.
  3. Keep confirmations on when nothing above scoped rights was found; it is not a safety rating.

The five triggers, each counted only in the default setup of the install command and only if no setting closes it: (1) it accepts connections from other machines without a login; (2) it runs commands that the model or the input chooses, without asking each time and without a container of its own around them; (3) it reads stored passwords or tokens of other programs and can send them to hosts that neither you nor its description name; (4) it is built to take hostile input, and by default it runs that input or passes it into a shell command or a file path; (5) it installs something that starts on its own at login or boot, or it creates users or keys on your machine.

Every finding carries evidence lines at the pinned commit; every finding needs a step that closes or contains its right; the highest code value over every shipped mode stays the ceiling for sandbox planning. Unknown never counts as harmless, and a quiet run never makes a word milder. Maintainers can dispute any sentence with evidence; a stricter word is published only after a 14-day window, and corrections stay visible on the page.

One notation, two forms

reach <level> · <verdict> in the badge, the feeds, catalog.json and field-guide-search: the code level and the lab verdict. Examples: reach 2 · beyond declared (3), reach 2 · as declared, reach ≥2 · not run yet, reach ? · not run yet. The plate and the catalog row carry the shorter form reach <level> · <word>, the code level with its level word, because the plate shows the code reading alone; the verdict stands beside it as the run state in words. “≥2” means level 2 with at least one right unknown. Long form: “reach 2 from code (open); lab: beyond declared on 3 of 6 rights: files, network, execution”.

Path and host lists (v0.1)

Anchors for Secrets and Persistence, and the basis of the lab sensors and canary files. Changes raise the method version.

List Entries
Credential paths (Secrets 3) ~/.ssh/, ~/.aws/, ~/.config/gcloud/, ~/.azure/, ~/.kube/, ~/.docker/config.json, ~/.netrc, ~/.gnupg/, ~/.npmrc, ~/.pypirc, browser profiles (~/.mozilla/, ~/.config/google-chrome/, ~/.config/chromium/), agent tokens (~/.claude/, ~/.claude.json, ~/.codex/, ~/.gemini/, ~/.openclaw/), .env* outside the working directory, /etc/shadow, /etc/sudoers*, /var/run/docker.sock, canary files
Persistence paths (Persistence 3) ~/.bashrc, ~/.zshrc, ~/.profile, ~/.config/autostart/, /etc/cron*, /var/spool/cron/, ~/.config/systemd/user/, /etc/systemd/system/, ~/.ssh/authorized_keys, /etc/passwd, /etc/sudoers.d/, agent configuration (CLAUDE.md, AGENTS.md, .claude/settings*.json, .mcp.json, ~/.claude.json, .codex/config.toml, .gemini/settings.json, ~/.openclaw/)
Lab hosts (Network 0) gateway.lab (model gateway, proxy), dns.lab
Test target (Network 1) target.lab plus the declared hosts of each run from declared.json; together the run allowlist, whose SHA-256 is in manifest.json
Package sources (install phase only, Network 1) registry.npmjs.org, registry.yarnpkg.com, pypi.org, files.pythonhosted.org, github.com, objects.githubusercontent.com, raw.githubusercontent.com, ghcr.io, registry-1.docker.io, auth.docker.io, crates.io, proxy.golang.org
Upload threshold (Network 3) more than 64 KB outgoing to an undeclared host within one run, or a canary string in egress (an estimate, calibrated in the first runs)

Evidence format

One evidence line per value: <file>#L<n>[-<m>] <reason>; several items separated by ; , each with its own file name. Without a line reference only two forms exist: none found: <what was searched> for 0 and no evidence: <reason> for “?”. Upstream paths are relative to the repository root at the pinned commit; lab paths point to a file in the same run folder. A value of 3 contains one sentence of justification.

Independence

Placement, badges or fast tracks are not sold. Sponsoring, should it ever exist, is marked separately and has no influence on tier or reach. The author is employed by an IT consultancy; the company has no influence on selection, execution or result.

Declaration of interests on every observation card: Private project, privately funded. The author is employed by an IT consultancy; the company is neither client nor sponsor of the measurement and had no influence on selection, execution or result. There is no business relationship with the maker of the tested tool, and no credits, licences or payments from tested vendors were accepted. Deviations are stated in this field.

Limits

  • One run is an observation, not a benchmark.
  • Server-side behaviour of remote MCP servers stays “?”.
  • The lab is not your production environment.
  • Static analysis can miss behaviour that appears only at runtime; that is why the Lab column exists.

Lab

Schatten-Administration: definition

Definition, German original, as of 2026-10-07:

Schatten-Administration ist die Ausübung von Rechten durch einen Agenten, die weder deklariert noch pro Aktion freigegeben ist, gemessen als beobachtete Reichweite über der deklarierten; wo ein Recht nicht deklariert ist, gilt der Aufgabenbereich des Werkzeugs als Maßstab. Sie ist unabhängig davon, ob der Agent inventarisiert ist.

English translation:

Shadow administration is an agent’s exercise of rights that were neither declared nor approved per action, measured as observed reach above declared reach; where a right is not declared, the tool’s task scope is the yardstick. It is independent of whether the agent is inventoried.

The last sentence separates the term from shadow AI and shadow agents, where “shadow” means unknown. The English terms are Privilege Reach for the scale (badge label reach) and Agent Privilege Surplus for the difference, with “declared vs observed” as the subtitle. Privilege Reach is not the shadow administration itself; it provides the measurement, and the difference is the finding.

What the surplus is not: it is not granted versus used (that is what permission-analytics products measure); it measures used against declared. Whether a right is needed cannot be determined reproducibly; that stays a human judgement, recorded as fit.

The dated definitions with their citation lines: Agent Privilege Surplus and Schatten-Administration.

Changelog

  • 0.1 (draft): first version. Reading model with three columns, reach level from the code, lab verdict in four words, one surplus formula with the task scope, one notation.
  • 0.1, 2026-11-07: how Approval is observed now names the lab approver hook and its task list; no reading changed.

Cite as

Ilja Schlak. “Rules of the method v0.1”. Agentic Security Field Guide, 2026. https://readbeforerun.ai/method/rules/