> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parmanasystems.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Audit guide

> The system under evaluation, where it blocks execution, what an attacker controls in each case, and how to record which attacks are blocked and which succeed.

This page is for a security reviewer or auditor. It defines the system being evaluated, the
code points where execution is refused, the attacker capabilities that are and are not in
scope, and a bounded scenario that can be reproduced from a pinned commit. Set up a clone
first with [Evaluate Parmana](/evaluation/overview).

## The system under evaluation

The enforcing system is the **Parmana server** in
[github.com/pavancharak/parmana](https://github.com/pavancharak/parmana): the API, the
runtime that evaluates policy and signs authorizations, the execution gateway, and the
connectors behind it.

[`@parmana/sign`](https://github.com/pavancharak/parmana-sign) is **not** an enforcement
component. It verifies signed records after the fact and decides nothing. A valid signature
on a Trust Record shows that Parmana signed that record and that it was not altered. It does
not show that an unauthorized action was prevented, and it says nothing about actions that
never passed through Parmana. Prevention is a property of the enforcement points below, and
of the downstream system only accepting requests that went through them.

## Where execution is blocked

A request to `POST /execute` passes these points in order. Each refuses before the next one
runs, and nothing reaches a downstream system unless every point passes.

| Point | Code | Refuses | Result |
| - | - | - | - |
| **E1. API boundary** | `packages/api/src/middleware/caller-auth.ts`, `packages/api/src/routes/execute.ts` | A missing or unknown API key; a capability the key is not allowed; a `tenantId` the key does not list | `401` or `403`; nothing is evaluated |
| **E2. Decision** | `packages/runtime/src/RuntimeEngine.ts`, `packages/approval/src/ApprovalSignalVerifier.ts` | A capability paired with a policy other than its bound one; declared facts that contradict the Intent; any policy rule that rejects; an approval signal without a valid signed approval for this action, resource and amount; a policy whose content does not match its signed approval record | `403 POLICY_DENIED` and a signed Refusal Record; no authorization is signed |
| **E3. Gateway** | `packages/execution-gateway/src/ExecutionGateway.ts` (`verify`, then `execute`) | A bad or unknown signature; an expired authorization; content whose hash differs from the signed hash; a policy that is no longer the approved, current version; signals that no longer match; a nonce already used | The connector is not called; a replay is `409` |
| **E4. Execution control** | `packages/execution-control/src/ExecutionControlService.ts`, `ConnectorPolicy.ts`, `CredentialVault.ts` | A connector call without a valid, unexpired, single use gateway session. Connector credentials are released only here | The connector refuses; no credential is released |
| **E5. Remote receiver** | Outside this repository: for example `parmana-paytm-agent`, or an [external connector](/guides/connect-any-external-system) endpoint | A release whose Parmana signature does not verify, if the receiver checks it | Depends on the receiver |

In Parmana's own server, E2 and E3 run in the same process for each request. E3 is the point
that matters when a receiving system runs separately and verifies authorizations itself
(`@parmana/envelope-verifier`). E5 is only as strong as the receiver's own check: Parmana
cannot stop a downstream system from accepting a request that never came through it.

## What an attacker controls

"Credential compromise" is not one thing. Each credential below is listed separately,
because the outcome differs. The expected outcome is what the code is designed to do; an
evaluation should record what is actually observed.

| Attacker holds | Controls | Expected outcome | In scope |
| - | - | - | - |
| Nothing (network access only) | Any HTTP request | Refused at E1 | Yes |
| A valid agent API key | The whole request body: action, target, parameters, declared signals, metadata | An action whose policy needs an approval is refused at E2 without one. Declared facts cannot authorize. Parameters an approval does not cover can still be chosen freely (see [Limitations](/security/limitations)) | Yes |
| A captured, valid authorization | Replaying it, or changing its parameters | Refused at E3: replay by the nonce, changes by the content hash, late use by expiry | Yes |
| A captured, used signed approval | Reusing it, or presenting it for another resource, amount or action | Refused at E2: single use, and bound to capability, resource, amount and scope field | Yes |
| An approver's private key | Signing approvals as that approver | **Succeeds** for any action and resource that approver is trusted for, until the key is revoked through maker checker | No (assumed) |
| Parmana's authorization signing key (`default`, local file or AWS KMS) | Signing authorizations | **Succeeds** against E3 and E5, which trust that key. Under AWS KMS the key cannot be exported, but a process that can call `kms:Sign` can still sign | No (assumed) |
| A connector's own credential (Paytm merchant key, HubSpot token, GitHub App key, Slack token) | Calling the downstream system directly | **Succeeds**. Parmana enforces nothing at the network level; a call that bypasses it is neither refused nor recorded | No (assumed) |
| The gateway key (`gateway`) | Signing gateway attestations and gateway sessions | **Succeeds** in forging an attestation that the gateway released an action. It does not by itself authorize an action at E2 or E3 | No (assumed) |
| Write access to Parmana's database | Rows in the policy, approver, nonce and record tables | Not covered. Some checks still hold (live policy content is compared with its signed approval record), but no claim is made against this attacker | No (assumed) |
| Both the maker and the checker credentials | Proposing and approving a policy change alone | **Succeeds**. Maker checker assumes two people. In the current production deployment one person holds both | No (assumed) |

SECURITY.md lists findings that need a compromised signing key or infrastructure as out of
scope. They are listed here anyway, so that a report can state them as assumptions rather
than leave them implicit.

## A bounded scenario: a refund without a valid manager approval

**Code versions.** Pin the commit you test and record it in the report:

```bash theme={null}
git clone https://github.com/pavancharak/parmana.git
cd parmana
git checkout f5e208c5   # main as of 2026-10-03; use a later commit if you prefer, and record it
npm ci && npm run build
```

* Policy: `policies/customer-refund/1.2.0/policy.json`. Every refund above 0 and up to 100000
  needs a signed manager approval for that order, covering that amount. Above 100000 is
  refused.
* Capability: `paytm:refund`, bound to `customer-refund` in
  `packages/capability-registry/src/CapabilityPolicyBinding.ts`.
* Offline verification of the resulting records: `@parmana/sign` 0.2.0.

**Attacker.** Holds a valid API key allowed `paytm:refund`, and controls the entire request
body, including every declared signal. Does not hold an approver key, Parmana's signing key,
the gateway key, Paytm credentials or database access.

**Attacks and expected outcomes.**

| Attack | Expected | Point | Test that exercises it (`packages/api/tests/integration/paytm-refund.integration.test.ts` unless named) |
| - | - | - | - |
| Declare every fact true, `managerApproved: true`, attach no approval | Blocked | E2 | "rejects managerApproved: true with no approval attached" |
| Attach an approval signed for a different order | Blocked | E2 | "rejects an approval signed for a different order" |
| Attach an approval whose amount limit is below the refund | Blocked | E2 | "rejects an approval whose amount limit is below the refund amount" |
| Attach an approval signed by an untrusted key | Blocked | E2 | "rejects an approval signed by a key that is not a trusted approver" |
| Change the signed amount limit inside a real approval | Blocked | E2 | "rejects an approval whose signed amount limit was changed after signing" |
| Reuse a valid approval on a second request | Blocked | E2 | "accepts an approval once: the same approval on a second, new request is rejected" |
| Pair `paytm:refund` with an unrelated, permissive policy | Blocked | E2 | "capability/policy binding: rejects ... when paytm:refund is paired with an unrelated, unprotected policy" |
| Declare a refund amount that differs from the executed amount | Blocked | E2 | "binding validation: rejects ... when the declared refund amount does not match" |
| Change the amount in a valid authorization before the gateway | Blocked | E3 | `packages/execution-gateway/tests/unit/execution-gateway.test.ts`: "rejects a modified amount" |
| Replay a valid authorization | Blocked | E3 | same file: "rejects a replayed request without releasing it twice" |
| With a valid approval for this order and amount | Executes once | none | "executes a refund above 10000 exactly once when it carries a valid signed manager approval" |
| Call Paytm directly with Paytm credentials | Succeeds | none | Not testable in Parmana; outside its control |

Run them:

```bash theme={null}
npx vitest run packages/api/tests/integration/paytm-refund.integration.test.ts
npx vitest run packages/execution-gateway/tests/unit/execution-gateway.test.ts
```

The same chain runs against a real Postgres, on a network with no internet route, with
`bash docker/local/offline-check/run.sh` (Docker). An auditor is encouraged to write further
attacks against the server running locally (`npm run dev`, or the Docker stack) rather than
rely only on the tests listed here.

## Recording results

A useful result is a reproducible account of which attacks were blocked, which succeeded, and
under which assumptions, not a pass or fail for the whole system. For each attack, record:

| Field | Example |
| - | - |
| Commit | `f5e208c5` |
| Attacker holds | Agent API key with `paytm:refund`; no approver or signing key |
| Attack | Approval for order A presented with a refund for order B |
| Expected | Blocked at E2 |
| Observed | `403 POLICY_DENIED`; connector call count 0 |
| Evidence | Command, response, server log line, Refusal Record |
| Assumptions | Approver key not compromised; database not writable by attacker |

An attack that succeeds is a finding even when it falls under a stated assumption: it shows
where the boundary actually is.

## Evidence documents

* [docs/CLAIMS.md](https://github.com/pavancharak/parmana/blob/main/docs/CLAIMS.md): every
  claim, scoped to its evidence. Summarised in [Claims and evidence](/evaluation/claims-and-evidence).
* [docs/VERIFICATION-GAPS.md](https://github.com/pavancharak/parmana/blob/main/docs/VERIFICATION-GAPS.md):
  every gap found, and how it was closed or narrowed.
* [docs/adr/](https://github.com/pavancharak/parmana/tree/main/docs/adr): architectural
  decisions.
* [Limitations](/security/limitations) and [Security](/security/overview).

## Review history

These are internal reviews by the developer, not independent audits.

* **2026-10-03.** A review of code, docs and claims found and fixed, among others:

  * a rejected policy change that could still be applied;
  * unauthenticated requests that could each trigger a signing call;
  * caller chosen tenant signing keys;
  * concurrent approvals of one policy change;
  * an unchecked approval scope field;
  * a gateway signal check skipped when signals were absent.

  See [pavancharak/parmana#6](https://github.com/pavancharak/parmana/pull/6),
  [pavancharak/parmana#7](https://github.com/pavancharak/parmana/pull/7) and
  [pavancharak/parmana#8](https://github.com/pavancharak/parmana/pull/8), and the
  [changelog](/changelog).

* Earlier reviews are recorded in docs/VERIFICATION-GAPS.md and in dated updates in
  docs/CLAIMS.md.

## Reporting

Report security issues privately to
[founder@parmanasystems.com](mailto:founder@parmanasystems.com), as described in
[SECURITY.md](https://github.com/pavancharak/parmana/blob/main/SECURITY.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.