GAL reference
Every verb in the GuardLink Annotation Language as guardlink 2.0.0
defines it. npx guardlink gal prints the same thing in your terminal,
which is faster while you are actually writing annotations.
For what the language is for, and how the verbs compose into a finding, see the annotation language.
Annotations live in source comments or standalone .gal files. GuardLink parses them into a live threat model for your codebase.
@verb subject [preposition object] [-- "description"]Inline examples below use comment prefixes; raw .gal files use the same lines without // or #. In .gal files, use @source file:<path> line:<n> [symbol:<name>] to anchor following annotations.
Definitions
Section titled “Definitions”@asset
Section titled “@asset”@asset <path> [-- "description"]Declare a named asset (component, service, data store). Path uses dot notation for hierarchy.
// @asset api.auth.token_store -- "Stores JWT refresh tokens"// @asset db.users@threat
Section titled “@threat”@threat <name> (#id) [critical|high|medium|low] [ext-refs] [-- "description"]Declare a named threat. Severity in brackets: [P0]=[critical] [P1]=[high] [P2]=[medium] [P3]=[low].
// @threat SQL Injection (#sql-inj) [high] cwe:CWE-89 -- "Unsanitized input reaches DB"// @threat Token Theft [P0]@control
Section titled “@control”@control <name> (#id) [-- "description"]Declare a security control (mitigation mechanism).
// @control Input Validation (#input-val) -- "Sanitize all user-supplied strings"// @control Rate Limiting@actor
Section titled “@actor”@actor <name> (#id) [-- "description"]Declare a principal in the authorization model — a role, not a person. Declared once per project, alongside @asset / @threat / @control.
// @actor Namespace_Admin (#ns-admin) -- "Administers one namespace's configuration"// @actor Namespace_Writer (#ns-writer) -- "Starts and signals workflows"Relationships
Section titled “Relationships”@exposes
Section titled “@exposes”@exposes <asset> to <threat> [severity] [ext-refs] [-- "description"]Mark an asset as exposed to a threat at this code location. This is the primary annotation — every exposure creates a finding.
// @exposes api.auth to SQL Injection [high] cwe:CWE-89// @exposes db.users to Token Theft [critical] -- "No token rotation"@mitigates
Section titled “@mitigates”@mitigates <asset> against <threat> [using <control>] [-- "description"]Mark that a control mitigates a threat on an asset. Closes the exposure — removes it from open findings. “using” is the primary keyword; “with” also accepted.
// @mitigates api.auth against SQL Injection using Input Validation// @mitigates db.users against Token Theft -- "Rotation implemented in v2"@confirmed
Section titled “@confirmed”@confirmed <threat> on <asset> [severity] [ext-refs] [-- "evidence"]Mark a threat as verified exploitable (pentest, scan, or manual repro). Not a false positive — use observed severity. Distinct from @exposes (hypothesis).
// @confirmed SQL Injection on api.auth [critical] cwe:CWE-89 -- "Pen test: blind SQLi on /login"// @confirmed #secret-exposure on App.Config [critical] -- "Live key in repo; verified with provider"@accepts
Section titled “@accepts”@accepts <threat> on <asset> [-- "reason"]Explicitly accept a risk. Removes it from open findings. Use when the risk is known and intentionally not mitigated.
// @accepts Timing Attack on api.auth -- "Acceptable for current threat model"@entitles
Section titled “@entitles”@entitles <actor> to <capability> [on <asset>] [against <threat>] [-- "description"]State that an actor is legitimately entitled to a capability by design — the answer to “is the caller already allowed to do this?”. <capability> is one identifier, never prose. The JOIN is (actor, asset, threat): a claim missing on or against joins nothing and cannot demote. Never suppresses a finding and never gates testing — it only informs the recommendation downstream. Absent from the SARIF export entirely. Must cite the authz code (file:line) in the description, or it is inert. Not written by hand and never by an agent: an over-grant closes a real escalation as by-design, so entitlements are proposed and then accepted. An @entitles with no accepted proposal behind it is a validation error.
// @entitles #ns-admin to configure-archival-destination on #archival-fs against #path-traversal// -- "By design: the archival URI is namespace config. Authz: common/api/metadata.go:189"guardlink entitle --propose --actor "#ns-admin" --capability configure-archival-destination \--asset "#archival-fs" --threat "#path-traversal" --file common/api/metadata.go --line 189 \--rationale "By design: namespace config. Authz: common/api/metadata.go:189"guardlink entitle # review proposals: accept / reject / deferguardlink entitle --list # see the ledger, .guardlink/entitlement-proposals.json@transfers
Section titled “@transfers”@transfers <threat> from <source> to <target> [-- "description"]Transfer responsibility for a threat to another asset/team.
// @transfers DDoS from api.gateway to cdn.cloudflare -- "Handled by CDN layer"Data Flows & Boundaries
Section titled “Data Flows & Boundaries”@flows
Section titled “@flows”@flows <source> -> <target> [via <mechanism>] [-- "description"]Document data movement between components. Appears in the Data Flow Diagram.
// @flows api.auth -> db.users via TLS 1.3// @flows mobile.app -> api.gateway via HTTPS -- "User credentials"@boundary
Section titled “@boundary”@boundary <asset_a> and <asset_b> (#id) [-- "description"]Declare a trust boundary between two assets. Groups assets in the Data Flow Diagram. Alternate: @boundary between A and B or @boundary A | B
// @boundary internet and api.gateway (#edge) -- "Public-facing edge"// @boundary api.gateway | db.users -- "Internal network boundary"Lifecycle & Governance
Section titled “Lifecycle & Governance”@handles
Section titled “@handles”@handles <classification> on <asset> [-- "description"]Declare data classification handled by an asset. Classifications: pii phi financial secrets internal public
// @handles pii on db.users -- "Stores name, email, phone"// @handles secrets on api.auth.token_store@owns <owner> for <asset> [-- "description"]Assign ownership of an asset to a team or person.
// @owns platform-team for api.auth@validates
Section titled “@validates”@validates <control> for <asset> [-- "description"]Assert that a control has been validated/tested on an asset.
// @validates Input Validation for api.auth -- "Pen-tested 2024-Q3"@audit
Section titled “@audit”@audit <asset> [-- "description"]Mark that this code path is an audit trail point.
// @audit db.users -- "All writes logged to audit_log table"@assumes
Section titled “@assumes”@assumes <asset> [-- "description"]Document a security assumption about an asset.
// @assumes api.gateway -- "Upstream WAF filters malformed requests"Feature Tagging
Section titled “Feature Tagging”@feature
Section titled “@feature”@feature "Feature Name" [-- "description"]Tag code with a feature name for filtering reports and dashboards. A file can have multiple @feature tags. All annotations in that file are associated with the tagged features. Filter commands by feature:
// @feature "SSO Login" -- "Single sign-on authentication flow"// @feature "Payment Processing"guardlink feature listguardlink report . --feature "SSO Login"guardlink dashboard . --feature "SSO Login,Payment Processing"@comment
Section titled “@comment”@comment [-- "description"]Free-form developer security note (no structural effect).
// @comment -- "TODO — add rate limiting before v2 launch"Shield Blocks
Section titled “Shield Blocks”@shield
Section titled “@shield”@shield [-- "reason"]Single-line marker for a security-sensitive code point.
// @shield -- "Crypto key derivation — do not refactor without review"@shield:begin
Section titled “@shield:begin”@shield:begin / @shield:endWrap a code block to mark it as security-sensitive. GuardLink will flag unannotated symbols inside the block.
// @shield:begin -- "Auth verification block"function verifyToken(token: string) { ... }// @shield:endExternal References
Section titled “External References”Append space-separated refs after severity on @threat, @exposes, and @confirmed:
cwe:CWE-89 owasp:A03:2021 capec:CAPEC-66 attack:T1190Example:
// @exposes api.auth to SQL Injection [high] cwe:CWE-89 owasp:A03:2021- Descriptions use – “quoted text” format (not : colon)
- Severity uses brackets: [critical] [high] [medium] [low] or [P0]-[P3]
- Annotations work in any comment style: // /* # – <!– –>
- Place annotations on the line ABOVE the code they describe
- Asset names are case-insensitive and normalized (spaces→underscores)
- Threat/control names can reference IDs with #id syntax
- @flows uses -> arrow syntax (not “to”)
- Run guardlink parse after adding annotations to update the threat model
- Run guardlink validate to check for syntax errors and dangling references
- Run guardlink annotate to have an AI agent add annotations automatically
- Run guardlink entitle to decide proposed @entitles claims — an agent drafts, a human accepts

