Skip to content

fix(accounts): limit policy enforcement event size - #896

Open
IvanBelyakoff wants to merge 3 commits into
OpenZeppelin:mainfrom
IvanBelyakoff:fix/accounts-bounded-enforced-events
Open

IvanBelyakoff wants to merge 3 commits into
OpenZeppelin:mainfrom
IvanBelyakoff:fix/accounts-bounded-enforced-events

Conversation

@IvanBelyakoff

@IvanBelyakoff IvanBelyakoff commented Sep 16, 2026 •

Copy link
Copy Markdown

Fixes #852

Includes #866, now merged into main.

Policy enforcement events currently copy authorization arguments and full signer data, which can exceed the transaction event-size limit.

This change:

  • Adds a shared EnforcedContext projection that keeps the target and function name for calls, or the executable and salt for deployments, while omitting call and constructor arguments.
  • Replaces full authenticated signer values with their registry IDs in simple and weighted threshold events.
  • Moves context_rule_id into topics across all three reference policies.

Policy checks and spending-limit argument handling are unchanged. The enforcement event schemas change, so consumers must update their decoders.

Tests cover large arguments, maximum external signer counts, signer-ID mapping, both deployment context variants, and complete event sizes at the ExternalRef ledger-key size boundary. All 196 account tests pass.

One Protocol 28 limitation remains: ExternalRef.tag is retained unchanged. The host can pass oversized tags to __check_auth, including through unused child authorizations. These can still exceed the event-size limit. This limitation is documented and covered by a serialization regression test; this PR does not introduce a tag-length restriction.

PR Checklist

  • Tests
  • Documentation

Summary by CodeRabbit

  • New Features
    • Enforcement events now report the context rule ID as a topic and include signer IDs aligned with the rule, rather than full signer details.
    • Event context identifies contract calls by target and function, and contract creation by executable and salt; call arguments and constructor arguments are not included.
    • Enforcement events are designed to stay smaller when calls or contract creation include large arguments, helping avoid oversized events. External-reference tags remain part of the context and can still increase event size.

@coderabbitai

coderabbitai Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 55a2a630-590e-4e48-8749-488b653ec8a0

📥 Commits

Reviewing files that changed from the base of the PR and between b40c5ea and 1be218e.

📒 Files selected for processing (9)
  • packages/accounts/src/policies/mod.rs
  • packages/accounts/src/policies/simple_threshold.rs
  • packages/accounts/src/policies/spending_limit.rs
  • packages/accounts/src/policies/test/enforced_context.rs
  • packages/accounts/src/policies/test/mod.rs
  • packages/accounts/src/policies/test/simple_threshold.rs
  • packages/accounts/src/policies/test/spending_limit.rs
  • packages/accounts/src/policies/test/weighted_threshold.rs
  • packages/accounts/src/policies/weighted_threshold.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

The three reference policies now publish enforcement events with projected contexts instead of complete authorization contexts. Threshold-policy events report signer IDs aligned with the context rule, and all three events place the context rule ID in their topics. New tests check event contents and serialized sizes.

Changes

Enforcement event payloads

Layer / File(s) Summary
Context projection and signer ID mapping
packages/accounts/src/policies/mod.rs
Adds EnforcedContext, which retains the contract target and function or the creation executable and salt, while omitting call and constructor arguments. Adds a helper to map authenticated signers to aligned context-rule signer IDs.
Policy enforcement event schemas
packages/accounts/src/policies/simple_threshold.rs, packages/accounts/src/policies/weighted_threshold.rs, packages/accounts/src/policies/spending_limit.rs
Updates event fields and publishing code to use EnforcedContext. Threshold-policy events include aligned signer IDs. Each event uses context_rule_id as a topic.
Projection and event-size tests
packages/accounts/src/policies/test/*
Adds tests for projected creation contexts, signer-ID mapping, and serialized event sizes. Tests cover large arguments, maximum signer counts, and external-reference tag sizes.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: brozorec

Merge Risk: ⚪ Minimal · up to 1be21

The event payload changes have no established new merge-blocking defect. Oversized ExternalRef tags remain a documented limitation, not a regression from this PR.

Security Architecture Review

Security architecture risk: 🟡 Moderate · up to 1be21

The smaller events address the reported size problem, but existing event decoders need to change with them. The available evidence does not establish whether downstream consumers are ready. An oversized deployment tag can still produce an oversized event, although that exposure existed before this PR.

Retained concerns

  • Medium · architecture · inferred: The three enforcement-event formats are incompatible with their previous layouts. Consumers that continue decoding the old topics or data may lose or misinterpret authorization telemetry until updated; whether any deployed consumer is affected is unknown.
Security review details

Security Blast Radius

  • inferred — The relevant exposure is authorization and event emission for smart accounts using these policies, including deployment contexts supplied by the host. The examined change does not establish a new cross-account authority, service privilege, or datastore boundary.

Security Findings and Attack Paths

  • inferred — An oversized host-supplied ExternalRef tag can pass through a matching or Default context rule into an enforcement event, including an unused child authorization. The regression test demonstrates oversized serialization, not a production host failure. Because the base event already contained the full context, this is a remaining limitation rather than an active PR-introduced concern.

Trust Boundaries and Controls

  • observed — The account binds rule IDs into the signed digest, rejects signers outside selected rules, and authenticates signers before invoking policies. Simple and weighted enforcement also require smart-account authorization and satisfy their thresholds before publishing. The new event projection is not used to make those decisions.

Resilience and Maintainability Implications

  • inferred — The spending-limit projection adds no new budget mutation or retry path: validation precedes one history update and one publication. Repository evidence does not directly verify host rollback of that update if publication itself fails because an event is oversized.

Hardening Proposals

  • proposed — Identify event consumers and coordinate decoder compatibility or versioning before adopting the changed event formats, particularly where events provide authorization audit signals.
  • proposed — Separately assess a bounded representation of ExternalRef identity in events and a host-level publication-failure rollback test. Neither is an implemented guarantee in this PR.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The changes satisfy the main #852 case for Context::Contract arguments and constructor arguments. EnforcedContext omits those fields for all three policies, and the events use compact u32 signer… Ensure the enforcement event cannot grow with an unbounded ExternalRef.tag. Bound, omit, or replace the tag with a fixed-size representation before publishing the event, and add boundary coverage for the resulting behavior.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changes remain within #852 scope. The compact context projection, signer-ID mapping, context_rule_id topic placement, event documentation, and size-boundary tests all support the enforcement-eve…
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 24 functions across 9 files.
Title check ✅ Passed The title clearly and concisely describes the main change: limiting policy enforcement event size.
Description check ✅ Passed The description identifies the related issue, explains the implementation, documents schema changes and the remaining ExternalRef.tag limitation, and completes the Tests and Documentation checklist it…
Full details: Linked Issues check

Explanation

The changes satisfy the main #852 case for Context::Contract arguments and constructor arguments. EnforcedContext omits those fields for all three policies, and the events use compact u32 signer IDs. However, ContractExecutable::ExternalRef retains its unbounded tag. The changed code documents that an oversized tag can still make an enforcement event exceed the transaction event-size limit. This leaves the linked issue's objective incomplete for caller-controlled context data.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

A rabbit checks the event stream bright
And trims the context down just right
The signer IDs line up in rows
While XDR size testing grows
Then hops away beneath the moon

Comment @coderabbitai help to get the list of available commands.

@brozorec

brozorec commented Sep 26, 2026 •

Copy link
Copy Markdown
Collaborator

#866 was merged, can you plz change the base of this PR to main

@brozorec brozorec reopened this Sep 26, 2026
Project authorization contexts to omit caller-controlled arguments, and
emit compact signer IDs instead of full signer values.

Move the context-rule ID into event topics and cover large payloads,
maximum external signers, malformed rule input, and Protocol 28
executable variants.
Replace the bare 16_384 in the ExternalRef tag growth assertion with
TX_MAX_CONTRACT_EVENTS_SIZE_BYTES, documented as the testnet
txMaxContractEventsSizeBytes measured in OpenZeppelin#852.
@IvanBelyakoff
IvanBelyakoff force-pushed the fix/accounts-bounded-enforced-events branch from 8a86219 to 1be218e Compare September 28, 2026 11:50
@IvanBelyakoff
IvanBelyakoff changed the base branch from p28-sdk-bump to main September 28, 2026 11:50
@IvanBelyakoff

Copy link
Copy Markdown
Author

@brozorec I've rebased the PR from main. Please review

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.

Enforced events embed the whole Context, so a policy-permitted call can exceed txMaxContractEventsSizeBytes and fail

2 participants