| Version | Supported |
|---|---|
| 0.10.x | Yes |
| < 0.10 | No — upgrade |
Fixes land on the current line only. This project has one maintainer, and a backport promise it will not keep is worse than an honest refusal: someone running an old version would wait for a patch that never arrives instead of upgrading. Releases are frequent and the changelog records every breaking change.
Do not report suspected vulnerabilities through public GitHub issues.
Email team@hlinor.ai with a description, reproduction steps, affected
version, and any known impact. We aim to acknowledge reports within 48 hours.
Please allow time for investigation and coordinated disclosure before
publishing details.
Hlinor Agent Registry is an open-source reference implementation of a portable policy manifest compiler and fail-closed action gate for AI agents. Version 0.10.x is the current stable line. Security issues include bypasses of strict action enforcement, acceptance of unlisted policy sources, signature or trust verification bypasses, path-boundary bypasses, and governed integrations executing a tool after a denial.
Configuration mistakes, permissive-mode behavior documented by the project, and policies that explicitly authorize an unsafe action are generally misuse or configuration issues rather than vulnerabilities. Reports showing that the documented behavior creates an unexpected security bypass are still welcome.
- Compilation reads only sources explicitly listed in the manifest.
- Absolute source paths and paths escaping the manifest directory are rejected.
- Unknown explicit entity types and case-colliding entity IDs are rejected.
- Compiled output is verified before atomically replacing an existing bundle.
- Production manifests reject permissive agents unless an explicit unsafe CLI override is supplied.
- Runtime enforcement reads a compiled JSON bundle, not authoring YAML files.
- A canonical SHA-256 digest detects accidental corruption and modifications made without recomputing the digest.
- Unknown agents and unknown actions in strict mode are denied.
- Blocked actions take priority over allowed actions.
- An allowance names its own basis.
EXPLICITLY_ALLOWEDmeans the action is on the allow list.ALLOWED_NOT_BLOCKLISTEDmeans permissive mode permitted an action the policy never mentions. The audit record does not present the second as the first. - Supported integrations raise a typed governance exception before executing the wrapped tool when a decision is denied.
ActionRequestandPolicyDecisionbind each evaluation to canonical request and bundle digests, bundle version metadata, actor, and environment context.- Signed bundles are verified against deployment-configured Ed25519 public keys. The signature covers the payload, digest, issuer, key ID, and validity window.
- Unknown signing keys, invalid signatures, expired signatures, and signatures issued too far in the future are rejected.
- Signing warns above a 90-day validity window and refuses above 366 days. Without a revocation channel, expiry is what forces a leaked bundle out of circulation.
- Trust store entries with a relative
public_key_pathmust stay inside the trust store directory. Absolute paths remain an explicit deployment choice. - A bundle declaring an
enforcement_modethe runtime does not recognize is rejected rather than coerced, so a compiler and runtime that disagree are visible instead of silently reconciled. - A deployment-controlled minimum bundle revision provides an explicit rollback floor.
- Parsed files are size-capped before they are read, so a truncated download or a wrong path fails with a diagnosis instead of exhausting memory.
- Runtime dependencies carry upper version bounds and GitHub Actions are pinned to commit SHAs, so neither changes under the project without a decision.
- A shared
PolicyBundleCacheis keyed by the resolved bundle path, the SHA-256 of the bytes read from disk, and a digest over every verification setting and trusted key — signature policy, required issuer, minimum bundle revision, clock skew, and each key's ID, issuer and raw public key. A file-backed trust store is re-read from disk before the key is derived, so a rotated or revoked key cannot reuse state verified under the previous one. A cache hit still re-checks the file fingerprint and re-runs the signature validity window, so caching skips re-verification of bytes, never of time. - Tool Contracts and drift checks operate before anything runs.
contract checkreportsUNSCOPED_ALLOW_PERMISSION,UNDECLARED_TOOL_SCOPE,STALE_ALLOW_PERMISSIONandSTALE_BLOCK_PERMISSION;contract diffadditionally reports contract identity, version, tool set, input schema, resource scope, effect and annotation changes. Exit codes separate aligned, drift found, and bad input, so CI can gate on the difference.
An unsigned bundle digest provides integrity checking, not authentication. A
party that can replace an unsigned bundle can also recompute its digest.
Version 0.5 adds Ed25519 bundle authentication, but trust store distribution,
private-key protection, and rollback-floor state remain deployment
responsibilities. Action patterns give resource-aware authorization when the
caller supplies ActionRequest.resource.
Argument-aware authorization is available only through the binding MVP.
PolicyChecker remains a name-and-resource policy engine and does not inspect
tool arguments by itself. BoundTool normalizes supported Python callables,
validates the normalized object against the reviewed Tool Contract JSON Schema,
records its RFC 8785 digest in the ActionRequest, and invokes the exact
retained callable only after the existing policy gate allows it. Unbound
callers and framework paths that do not use BoundTool are not covered by
this argument check.
- Use
enforcement_mode: strictfor production agents. - Review manifests and policy sources through a protected change process.
- Restrict write access to compiled bundles and their deployment path.
- Require signed bundles with a deployment-owned trust store and expected issuer.
- Set
minimum_bundle_revisionfrom protected deployment state. - Deploy bundles as complete files and monitor digest changes.
- Treat the existing JSONL decision events as application audit records, not
immutable receipts. Use
HashChainedReceiptSinkor the checkpointed, fsync-backedJsonlReceiptSinkfor the experimental execution-receipt path; configure Ed25519 signing and an external protected collector for high-assurance deployments. Resume a JSONL chain only with explicit checkpoint verification. - Validate framework and dependency versions in your own environment.
- Use a
requires_approvalpolicy for high-impact actions, keep the system that grants approvals outside the agent process, and pass its detached token throughBoundTool.invoke()with trusted keys and a shared replay guard. DirectPolicyCheckersignals remain a compatibility mechanism and do not authenticate the approver.
- Direct KMS/HSM signing providers are not implemented; the CLI currently reads an unencrypted PEM Ed25519 private key from a protected file.
- Rollback enforcement requires an external trusted minimum revision. A stateless verifier cannot detect rollback by itself.
- Trust-store distribution, key revocation rollout, and private-key custody are deployment responsibilities.
- The runtime checker is a name-and-pattern gate over the action and the
resource string the caller supplies. Policy schemas describing budget, rate,
evidence, or approval controls are not automatically enforced by
PolicyChecker. - A resource-scoped decision is only as good as the resource string the caller
passes.
PolicyCheckercannot verify thatreport:quarterly/q1is the file the tool actually opened; the adapter that builds theActionRequestowns that correspondence. Derive the resource from the same value the tool will use, not from a parallel one. *in a pattern crosses the:separator, sosend:email:*also coverssend:email:external:someone.hlinor-registry lintwarns when an allow pattern covers a block pattern beside it, but the warning is advisory: nothing prevents compiling a bundle whose allow list is broader than its author intended.- Policy attribution covers typed policies only.
matched_policy_idsnames the compiled policies whose trigger matched the request. An agent'spolicies:entry with no compiled policy behind it is documentation and never appears there, so an empty list means "no typed policy applied", not "no declared constraint was relevant".hlinor-registry compileprints which entries are enforced and which are not. - Policy signals are asserted by the caller, not verified. A
requires_approvalpolicy enforces that the request carries an approval bound to it and inside the freshness window; it cannot establish that a human ever granted that approval.PolicyCheckerruns inside the process it governs and has no independent channel to an approval system. The same holds for evidence claims and failure counts. These gates stop omissions and mistakes -- an adapter that forgot to wire approval, an approval replayed onto a different request, a stale claim -- and do not stop an adapter that fabricates the signal. Making them resistant to that requires the approval to be independently verifiable, for example a signed token checked against a trust store the way bundles already are, which is not implemented. - Freshness is bounded on both sides. A signal timestamp more than 30 seconds
ahead of the checker's clock is refused rather than treated as very fresh;
the allowance exists because machines disagree by seconds, not because a
future timestamp is acceptable.
bind_to_requestandsame_resourcemust be real booleans in both the authored file and the compiled bundle, so a binding check cannot be disabled by a value that is merely falsy. - A
failure_thresholdpolicy compares a count the caller reports. The checker keeps no state between requests, deliberately: an in-process counter would reset on restart and would not be shared between workers, so it would report a protection that a second process does not have. What the bundle contributes is the threshold as a reviewed, signed number rather than a constant in application code. - The experimental
SQLiteCircuitBreakeris a separate runtime control that records failures outside caller-provided signals and persists open state across workers and restarts. It currently covers repeated tool exceptions; returned error values, cost/rate/concurrency budgets, fan-out limits, and a propagated global kill switch still require adapter or control-plane work. - The binding MVP does not attest deployment provenance. It compares the reviewed and observed Tool Contract digests, retains the exact callable references supplied by the caller, validates normalized arguments, and avoids late name lookup. The caller must export the observed contract from those exact runtime objects. A compromised process can still lie about its observed contract, and the MVP does not verify an OCI image, wheel provenance, signed approval, or independently authenticated execution receipt. Those remain later RFC 0001 stages.
- Signed approval tokens are verified by the experimental
BoundToolpath and are bound to agent, action, tool, resource, normalized arguments, session and tenant.InMemoryReplayGuardis only suitable for tests and one-process development; a production replay guard must be atomic and durable across workers. The legacyPolicyCheckerAPI still accepts asserted approval signals by design. - Execution receipts can be hash-chained and Ed25519-signed, but a sink inside
the governed process is not an independent witness.
JsonlReceiptSinksupports fail-closed resume through an explicit verified checkpoint, andFailClosedReceiptSinkdefines the no-retry collector boundary. An independently operated collector, its availability policy, and protected deployment of both stores remain deployment work. - A policy-test suite proves the bundle decides as the suite says for the requests the suite lists. It is a regression net over authored intent, not evidence that the intent is safe or the request set is complete.
- YAML alias expansion is not bounded. Size limits cap the input, but a small file with nested anchors can still expand disproportionately. Policy sources are named explicitly in a manifest the deployment controls, so this is a self-inflicted denial of service rather than an attack path; compile in an environment where that is acceptable.
- LangChain and CrewAI compatibility is limited to the versions listed in the integration compatibility matrix and may require application-specific integration testing.