Skip to content

feat(audit-guard): add RelayerTxScanner for unauthorized TX detection (closes #25)#69

Open
gbengaeben wants to merge 2 commits into
Vero-protocol:mainfrom
gbengaeben:issue-25-relayer-tx-scan
Open

feat(audit-guard): add RelayerTxScanner for unauthorized TX detection (closes #25)#69
gbengaeben wants to merge 2 commits into
Vero-protocol:mainfrom
gbengaeben:issue-25-relayer-tx-scan

Conversation

@gbengaeben

Copy link
Copy Markdown
Contributor

Summary

Closes #25 (feat: relayer unauthorized tx scan).

Adds a RelayerTxScanner that screens every relayed transaction against an allowlist of authorized signers, with optional hard denylist, optional multi-sig threshold, and an optional trusted source-account list. Every scanned TX produces a structured TxScanResult with violations, warnings, and an AUTHORIZED / REQUIRES_REVIEW / UNAUTHORIZED status flag that the incident-response pipeline can consume.

What is new

File Purpose
src/audit-guard/src/relayer-scanner.ts RelayerTxScanner class + types (TxData, WhitelistConfig, TxScanResult, RELAYER_RULES)
src/audit-guard/src/relayer-scanner.test.ts 27 tests across 8 describe blocks
src/audit-guard/policies/relayer_authz.rego OPA/Rego mirror with the same rule identifiers and severities
src/audit-guard/src/cli.ts new scan-tx command (TX_DATA_FILE, RELAYER_CONFIG, RELAYER_AUTHORIZED_SIGNERS, RELAYER_DENYLIST, RELAYER_MULTISIG_THRESHOLD, REPORT_FILE)
src/audit-guard/src/index.ts re-exports RelayerTxScanner, RELAYER_RULES, types
src/audit-guard/README.md Relayer TX Scanner section

Status semantics

Status Trigger
AUTHORIZED All signers in allowlist, no foreign-signer violations
REQUIRES_REVIEW No HIGH/CRITICAL violation, but at least one warning (e.g. untrusted source, multi-sig shortfall only)
UNAUTHORIZED Any HIGH/CRITICAL violation (foreign signer / denylisted / empty signers / threshold miss + foreign signer)

Rules emitted

Rule Severity
EMPTY_SIGNERS CRITICAL
DENYLISTED_SIGNER CRITICAL
UNAUTHORIZED_SIGNER HIGH
MULTISIG_THRESHOLD_NOT_MET MEDIUM (warning) / HIGH (when combined with a foreign signer)
UNVERIFIED_SOURCE_ACCOUNT MEDIUM (warning)

Configuration

Configurable via JSON file or env vars. Fail-closed default — an empty allowlist rejects every TX until a config is supplied.

{
  "authorizedSigners": ["G...alice", "G...bob"],
  "denylist":          ["G...banned"],
  "multisigThreshold": 2,
  "sourceAccounts":    ["G...trusted-relayer"]
}
Env var Description
RELAYER_CONFIG Path to relayer config JSON
RELAYER_AUTHORIZED_SIGNERS Comma-separated allowlist override
RELAYER_DENYLIST Comma-separated denylist override
RELAYER_MULTISIG_THRESHOLD Numeric threshold override

CLI

node dist/cli.js scan-tx ./tx-data.json
RELAYER_CONFIG=./relayer.config.json \
  REPORT_FILE=./report.md \
  node dist/cli.js scan-tx

Exit code is 1 on UNAUTHORIZED, 0 otherwise (suitable for CI gates).

Drive-by fix

src/audit-guard/src/policy-engine.ts had a pre-existing TS2339 referencing the undeclared result.maintenance_alert on EvaluationResult. That error blocked tsc --noEmit for the whole package (so any PR here would have failed CI). Added the optional field on the interface and populated it from prData.maintenance_mode / prData.maintenance_message in the evaluate() method. Without this, the upstream CI would reject this PR on a red check before reviewers even saw the content.

Tests

  • npx tsc --noEmit — clean.
  • npx jest — 48/48 in src/audit-guard (27 new scanner tests + the existing policy-engine / backup suites).
  • Every scanner rule has a positive case; the denylist / unauthorized boundary, multi-sig warning vs. violation escalation, env-var overrides, fail-closed default, and discover() env-path are all asserted.

Out of scope (left for follow-ups)

  • Weighted multi-sig (the current multisigThreshold is a plain authorized-count threshold).
  • Pairing the scanner with the verifiable-audit-trail package to persist findings as part of the audit trail automatically.
  • GitHub Actions workflow that wires scan-tx into CI.

… (issue Vero-protocol#25)

Resolves Vero-protocol#25: relayer unauthorized tx scan.

Implements a RelayerTxScanner class that screens relayed transactions
against an allowlist of authorized signers, with optional hard denylist,
multi-sig threshold support, and a trusted source-account list. Every
scanned TX produces a structured TxScanResult with violations, warnings,
and an AUTHORIZED / REQUIRES_REVIEW / UNAUTHORIZED status flag that the
incident-response pipeline can consume.

Highlights:
- Configurable via JSON file or env vars (RELAYER_CONFIG,
  RELAYER_AUTHORIZED_SIGNERS, RELAYER_DENYLIST,
  RELAYER_MULTISIG_THRESHOLD).
- Fail-closed default: an empty allowlist rejects every TX until a
  config is supplied.
- Defense in depth: denylisted signers produce CRITICAL violations
  regardless of allowlist membership; threshold misses combined with a
  foreign signer escalate to HIGH.
- OPA/Rego mirror in policies/relayer_authz.rego for orgs that centralize
  policy in OPA.
- New CLI command: 'scan-tx <tx-data.json>'.

Drive-by fix: src/policy-engine.ts had a pre-existing TS2339 error
referencing result.maintenance_alert on EvaluationResult. Added the
optional field and populated it from prData.maintenance_mode /
maintenance_message so the package typechecks cleanly under strict mode.

Tests: 27/27 in src/relayer-scanner.test.ts (allowlist, denylist,
multi-sig escalation + warning, source-account warnings, env-var
overrides, discover(), boundary letter-spacing). 48/48 of the audit-guard
test suite as a whole passes.
@N-thnI

N-thnI commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Please resolve conflicts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: relayer unauthorized tx scan

2 participants