Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: pnpm/action-setup@v4
with:
version: 11.7.0
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
- uses: pnpm/action-setup@v4
with:
version: 11.7.0
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/security-rc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: G4 security-ready RC

on:
pull_request:
paths:
- ".github/workflows/security-rc.yml"
- "audits/g4/**"
- "contracts/src/**"
- "contracts/test/**"
- "contracts/script/Deploy.s.sol"
- "contracts/foundry.toml"
- "scripts/security-rc-gate.mjs"
- "scripts/security-rc-gate.test.mjs"
- "package.json"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: security-rc-${{ github.ref }}
cancel-in-progress: true

jobs:
evidence:
name: G4 scope and evidence integrity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true
persist-credentials: false
- uses: pnpm/action-setup@v4
with:
version: 11.7.0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- uses: foundry-rs/foundry-toolchain@v1
with:
version: v1.7.1
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install forge-std
if: hashFiles('contracts/lib/forge-std/src/Test.sol') == ''
run: cd contracts && forge install foundry-rs/forge-std@v1.16.2 --no-git
- name: Validate frozen scope and residual risks
run: pnpm security:scope
- name: Test the security gate
run: pnpm security:test
- name: Run Solidity tests
run: cd contracts && forge test
- name: Validate external review when present
if: hashFiles('audits/g4/external/external-review.json') != ''
run: pnpm security:rc
- name: Record pending external review
if: hashFiles('audits/g4/external/external-review.json') == ''
run: |
echo "External Solidity review is still pending." >> "$GITHUB_STEP_SUMMARY"
echo "This workflow validates preparation only; release:check remains blocked." >> "$GITHUB_STEP_SUMMARY"
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable implementation and protocol changes are recorded here.

### Added

- Provisional external-review intake and reviewer follow-up for G4, plus focused
regression tests proving ERC-1271 `STATICCALL` blocks state-changing callbacks
and invalid ECDSA `v` values are rejected.
- G4 security-ready RC preparation: a commit- and SHA-256-pinned Solidity audit
scope, internal review record, canonical residual-risk register, external-review
request/template, evidence-integrity workflow, and an adversarially tested gate.
`security:scope` validates preparation; `security:rc` additionally requires a
real independent report and blocks release until one is accepted.
- Clean-checkout conformance gate with separate Solidity, core TypeScript, and
dependency-isolated TypeScript Golden Vector suites. Each run records the
source commit/tree, vector SHA-256, tool versions, canonical outputs, suite
Expand All @@ -30,6 +38,12 @@ All notable implementation and protocol changes are recorded here.

### Changed

- The EIP-7702 residual ECDSA path is now called out prominently in the security
policy. The preliminary external-review email does not satisfy the G4 gate
until its scope/API discrepancies and reviewer-owned evidence are corrected.
- Release checks now require the complete G4 external-review gate. The 2026-07-26
Sepolia `AuditGrant` address is explicitly deprecated and cannot be used as
evidence for the corrected candidate.
- **Breaking (extension):** `DeletionAttestation.attest` now takes
`bytes32 evidenceCommitment` instead of `bytes calldata evidence`. Callers must hash
off chain and retain the preimage as a private witness.
Expand All @@ -39,6 +53,10 @@ All notable implementation and protocol changes are recorded here.

### Fixed

- **High (extension):** `AuditGrant` now persists each grant's origin Space and
rejects cross-Space acknowledgement or revocation. Previously, the controller
of another registered Space could revoke a victim grant by supplying its own
`spaceId`, and an auditor could emit a misattributed acknowledgement event.
- `DeletionAttestation` no longer publishes raw deletion evidence in transaction
calldata, which contradicted architecture invariant 9 and the rule against exposing
raw private payloads through a public wrapper.
Expand Down
34 changes: 34 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,40 @@ The contracts and packages are pre-release research software and have not been
declared production ready. Do not use them to custody value or publicize private
memory without an independent review of the exact deployed commit.

## G4 security-ready candidate

The `G4-rc1` Solidity target is frozen at
`af5a75fb2db532fd5603554083d8895a825c2de2`. Its scope, internal review, and
remaining risks are recorded under [`audits/g4/`](audits/g4/).

Current status: **provisional review received; corrections and publication
evidence pending; G4 not complete**.

- `pnpm security:scope` verifies the source commit, tree, compiler settings,
per-file hashes, full scope, and residual-risk register.
- `pnpm security:test` exercises forged self-review, weakened scope, path
traversal, digest mismatch, missing risk mapping, and unresolved High findings.
- `pnpm security:rc` additionally requires a qualifying independent report and
fails until that report is accepted.
- `contracts/src/experimental/MemoryMarket.sol` is outside G4 and must not inherit
any security-ready label from the core review.

### EIP-7702 authorization warning

Registry authorization is an ordered OR rule: a direct call by the signer, then
ERC-1271 approval, then canonical ECDSA recovery. For an EIP-7702-delegated EOA,
a delegate that rejects, reverts, pauses, or returns malformed ERC-1271 data does
not veto a valid signature from the EOA's underlying key. This residual ECDSA path
is an explicit protocol rule, not an ERC-1271 policy-enforcement guarantee.

Use an independently deployed contract-account controller or authorizer when an
ERC-1271 policy must be the exclusive authorization path. Do not use a delegated
EOA for that requirement. This condition is tracked as `G4-R-003`.

The earlier Sepolia `AuditGrant` deployment predates the cross-Space authorization
fix and is deprecated. See
[`docs/security/residual-risks.md`](docs/security/residual-risks.md).

Report vulnerabilities privately through the repository's GitHub Security
Advisory feature. Include affected versions, impact, reproduction steps, and a
minimal test when possible. Do not put secrets, user memory, salts, keys, or
Expand Down
77 changes: 77 additions & 0 deletions audits/g4/EXTERNAL_REVIEW_REQUEST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# External Solidity Review Request: ERC-8350 G4-rc1

Status: **provisional email received; corrections and evidence still required**

ERC-8350 needs one independent Solidity security review before the reference
contracts can be called a security-ready release candidate. This request is open
to an established auditor, security researcher, or independent Solidity team
with no maintainer role in AwareLiquid/ERC-8350.

The 2026-07-31 email review is recorded in
[`external/REVIEW_INTAKE_2026-07-31.md`](external/REVIEW_INTAKE_2026-07-31.md).
It does not complete G4 until the scope/API discrepancies are corrected and the
required reviewer-owned evidence package is published.

Public coordination issue:
[AwareLiquid/ERC-8350#11](https://github.com/AwareLiquid/ERC-8350/issues/11).

## Frozen target

- Repository: https://github.com/AwareLiquid/ERC-8350
- Source commit: `af5a75fb2db532fd5603554083d8895a825c2de2`
- Source tree: `f8d66277123391ea54de3f53842256e17e2a497e`
- Immutable source ref: `refs/tags/audit/g4-rc1-source`
- Scope manifest: `audits/g4/scope.json`
- Scope SHA-256: `c9db7d27957c86386d8842687a2d009c0ca03bc864307e88cfed0ee25f3ae9bf`
- Compiler: Solidity `0.8.24`, optimizer 200 runs, Cancun EVM
- Solidity source lines: 895 across libraries, interfaces, core, three
extensions, and the deployment script (including comments)

`contracts/src/experimental/MemoryMarket.sol` is explicitly excluded. It transfers
value, has a different trust model, and is not deployed by `Deploy.s.sol`.

## Priority questions

1. Can any account register, take over, rotate, or append to another Memory Space?
2. Do EIP-712, sequence, root, nonce, and Registry-domain bindings prevent mutation
and replay in every authorization path?
3. Are EOA, ERC-1271, malformed return, revert, and EIP-7702 fallback behaviors safe
and accurately represented?
4. Can any extension act against or emit authoritative-looking events for the wrong
Space, controller, transition, grant, or auditor?
5. Can public calldata or events expose raw memory, locators, salts, evidence, or
otherwise undermine the stated commitment model?
6. Do compiler settings, deployment code, sentinels, casts, and external calls
introduce unexpected behavior?

Please specifically assess `G4-R-003`, the normative EIP-7702-to-ECDSA fallback,
and verify the fix for `G4-INT-001`, the former cross-Space `AuditGrant` revocation.

## Reproduce

From the branch containing this audit packet:

```bash
pnpm install --frozen-lockfile
pnpm security:scope
pnpm check
cd contracts
forge test -vv
```

## Required evidence

1. Publish a report at a stable public URL in a repository controlled by the
reviewer or the review organization.
2. Identify the exact source commit and scope-manifest SHA-256 above.
3. Disclose independence, compensation, prior project work, and other conflicts.
4. Give every finding a stable ID, severity, status, rationale, and verification.
5. Leave no unresolved Critical or High finding.
6. Map every accepted Medium/Low/Informational finding into
`audits/g4/residual-risks.json`.
7. Submit the report, its SHA-256, and a completed copy of
`external/external-review.template.json` in a pull request.

The machine gate validates scope and evidence integrity; it does not decide whether
a reviewer is competent. Maintainers must still assess reviewer identity, method,
conflicts, and finding quality before accepting the report.
88 changes: 88 additions & 0 deletions audits/g4/INTERNAL_REVIEW.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# G4 Internal Solidity Review

Status: **complete as internal preparation; not an external audit**

- Candidate: `G4-rc1`
- Frozen source commit: `af5a75fb2db532fd5603554083d8895a825c2de2`
- Review date: 2026-07-31
- Solidity: `0.8.24`
- Foundry: `1.7.1`
- Slither: `0.11.6` (102 detectors)

This review prepares a stable target for an independent reviewer. It cannot satisfy
`External review complete` because the work was performed inside the project.

## Method

1. Manually traced registration, controller rotation, transition authorization,
state advancement, lookup behavior, and extension-to-Registry trust boundaries.
2. Reviewed EIP-712 field coverage, replay domains, ECDSA malleability handling,
ERC-1271 malformed/revert behavior, and the EIP-7702 fallback rule.
3. Reviewed all formal extensions for cross-Space authorization, public-data
disclosure, sentinel values, stale controller behavior, and event attribution.
4. Ran Slither against the formal Solidity scope with experimental, test, and
script paths filtered.
5. Ran all unit, Golden Vector, demo, and invariant tests.

## Actionable finding

### G4-INT-001: Cross-Space AuditGrant revocation and event misattribution

- Severity: **High**
- Status: **Fixed**
- Affected revision: all `AuditGrant` versions before source commit `af5a75f`
- Fixed revision: `af5a75fb2db532fd5603554083d8895a825c2de2`

`AuditGrant` derived a grant ID from its origin Space but did not persist that
Space. `revoke(spaceId, grantId)` authorized the controller supplied by the caller,
not the controller of the grant's origin Space. A controller of any other registered
Space could therefore revoke a victim grant. An auditor could also acknowledge a
grant while supplying another Space, producing a misattributed event.

The fix stores the origin Space for every grant and rejects `acknowledge` and
`revoke` when the supplied Space differs. Regression tests cover both cross-Space
paths and assert the persisted origin through `spaceOf`.

The Sepolia `AuditGrant` at
`0x20145Ab83958CFB321221e8a8C68181C818241B2` predates the fix and is deprecated.
It must not be used as evidence that the corrected extension is security-ready.

## Static-analysis disposition

Slither returned six detector results and no actionable issue after manual
triage. The machine-readable record is
[`internal/slither-summary.json`](internal/slither-summary.json).

| ID | Detector | Reported impact | Disposition |
|---|---|---:|---|
| `G4-SLITHER-001` | strict equality on the non-zero grant sentinel | Medium | False positive |
| `G4-SLITHER-002` | unused Registry head fields | Medium | Intentional |
| `G4-SLITHER-003` | unused authorization tuple fields | Medium | Intentional |
| `G4-SLITHER-004` | timestamp dataflow on a root comparison | Low | False positive |
| `G4-SLITHER-005` | bounded ECDSA calldata assembly | Informational | Intentional |
| `G4-SLITHER-006` | ERC-1271 low-level `STATICCALL` | Informational | Required behavior |

## Reproduce

```bash
cd contracts
forge fmt --check
forge test -vv

slither . \
--compile-force-framework foundry \
--exclude-dependencies \
--filter-paths 'src/experimental|test|script'
```

Observed Foundry result: **48 passed, 0 failed**, including one invariant suite
with 256 runs and 128,000 handler calls.

## Limitations

- This is not independent and does not complete G4.
- Slither findings are heuristics; a clean disposition is not proof of safety.
- `MemoryMarket` is experimental and explicitly outside this review.
- Off-chain encryption, salt generation, witness availability, wallet policy,
and deployment operations remain profile or deployment responsibilities.
- Any scoped source or compiler-setting change invalidates the external review.
Loading
Loading