Description
This documentation and security-review issue audits every merged PayStream contract entry point for correct Soroban authorization, correct authorized identity, safe check ordering, and intentional public-read exposure.
No production-code change is expected. Any discovered authorization defect must receive a separate high-priority security issue and fix.
Run this audit after the maintainer freezes the Plan Management and Usage-Based Billing features included in scope.
Requirements and Context
Create:
docs/decisions/auth-audit.md
Complete entry-point inventory
Derive the list from the merged #[contractimpl], generated contract specification, and any additional implementation blocks. Do not rely only on issue descriptions.
For every public function record:
- function name and signature;
- mutation or read-only classification;
- assets/state affected;
- intended authorizer;
- address source used for authorization;
- actual
require_auth() or require_auth_for_args() call;
- position of the auth check relative to storage writes and external calls;
- cross-contract authorization implications;
- public data exposed when no auth is required;
- result: correct, mismatch, intentionally permissionless, or requires design review;
- linked remediation issue where applicable.
The PR description must contain a concise version of the audit table, and the full table must live in the decision document.
Expected authorization model
Verify against actual merged behavior rather than assuming the following remains correct:
-
Merchant-authorized operations:
- plan creation;
- plan version creation;
- token/pricing/trial configuration where merchant-owned;
- usage recording;
- other merchant-owned mutations.
-
Subscriber-authorized operations:
- subscription creation;
- cancellation;
- upgrade;
- downgrade;
- migration to a newer plan version;
- subscriber-controlled caps, slippage, or payment preferences.
-
Administrator-authorized operations:
- initialization and token/router/oracle allowlist/configuration functions, where implemented.
-
Intentionally permissionless operations:
charge(), subject to due time, active state, allowance, token approval, and other merged safeguards.
-
Public read operations:
get_plan();
get_subscription();
get_usage();
get_usage_report();
- preview functions actually merged;
- allowlist/configuration reads where public by design.
Do not assume every function listed above exists. Mark only merged entry points as implemented.
Required attack review
For every mutation, test whether a caller can:
- pass another user's address without that address authorizing;
- pass a merchant address they do not control;
- reference another user's subscription and mutate it;
- select a plan/group/version owned by another merchant;
- change token, router, oracle, pricing, trial, or administrative configuration;
- record usage for a subscription belonging to another party;
- reuse authorization intended for different arguments;
- exploit an auth check performed after a state write or external call;
- exploit legacy/missing storage metadata to bypass ownership;
- exploit migration/versioning to change the authorized merchant or token;
- use a contract address as authorizer under assumptions valid only for account addresses.
Pay special attention to functions accepting an Address argument. Prefer authorization derived from trusted stored state after loading the relevant object, except during safe initialization/creation where the supplied identity itself must authorize.
Permissionless charge review
charge() is intentionally callable by anyone. Confirm that this does not grant callers control over:
- subscriber;
- merchant;
- token;
- price;
- usage;
- plan/version;
- destination;
- allowance;
- schedule.
Document potential griefing implications, including repeated catch-up charges for overdue subscriptions, even when transfers are formally authorized. Permissionless does not mean risk-free.
Read-only and privacy review
No-auth reads are expected, but the audit must document what they expose. Do not state that read-only data is non-sensitive merely because it cannot mutate state.
Review exposure of subscriber/merchant addresses, plan terms, due timestamps, usage, pricing, allowance, payment preferences, and version/migration state.
If public exposure conflicts with the final privacy model, open a separate design issue. Do not add ad hoc read authentication in this audit PR.
Soroban auth semantics
Verify conclusions against Soroban SDK 27.0.3 and official Stellar/Soroban documentation.
Document:
require_auth() versus require_auth_for_args();
- authorization trees for cross-contract calls;
- account versus contract authorization;
- generated client and transaction-simulation behavior;
- why source-account signature alone may not satisfy every required authorization;
- auth behavior during nested token/router/oracle calls.
Do not generalize PayStream's historical nested approve() failure into an unsupported claim about all cross-contract auth.
Test evidence
Tests using env.mock_all_auths() cannot alone prove that the correct identity was required.
Where feasible, add or reference focused security tests using explicit mocked auth and authorization-tree assertions to confirm:
- correct address authorizes;
- wrong/no authorization fails;
- exact arguments are covered where relevant;
- read functions require no auth as intended;
- permissionless charge requires no caller auth;
- failure leaves state unchanged.
If tests exceed documentation-only scope, create a linked test issue with exact cases.
Vulnerability handling
If a missing or incorrect auth check is found:
- notify the maintainer promptly;
- create a high-priority linked security issue;
- avoid unnecessary exploit details before a fix is available;
- do not silently fix production code in the audit PR;
- mark affected functions and deployment/version scope;
- recommend redeployment or migration review if deployed Wasm is affected.
Suggested Execution
- Branch name:
security/require-auth-audit
- Files to touch:
docs/decisions/auth-audit.md
docs/ARCHITECTURE.md only for a discoverability link
- no contract code
- Example commit message:
docs(security): audit require_auth usage across contract entry points
Test and Commit Steps
- Freeze and record the source commit included in the audit.
- Enumerate entry points from source and generated specification.
- Build the intended-versus-actual authorization table.
- Review attacker-controlled addresses, stored ownership, check ordering, permissionless charge, public reads, and cross-contract auth.
- Gather explicit test evidence or open a linked test issue.
- Open separate remediation issues for every mismatch.
- Verify:
rg "pub fn|require_auth|require_auth_for_args|mock_all_auths|mock_auths" src docs
Test-Path "docs/decisions/auth-audit.md"
git diff --check
- Commit with:
git add docs/decisions/auth-audit.md docs/ARCHITECTURE.md
git commit -m "docs(security): audit require_auth usage across contract entry points"
Only stage docs/ARCHITECTURE.md if changed.
Guidelines
- Comment with the source commit and feature scope to request assignment.
- Do not start or open a PR until assigned by a maintainer.
- The PR description must include
Closes #<issue-number>.
- Keep production-code fixes in separate linked security issues.
- Do not rely solely on
mock_all_auths() as authorization evidence.
- Derive ownership from trusted stored state where applicable.
- Document intentionally permissionless and public functions explicitly.
- Handle real vulnerabilities promptly and avoid unnecessary premature exploit disclosure.
- Do not upgrade Soroban SDK from
27.0.3.
- Follow Conventional Commits and repository branch conventions.
Complexity
High (200 pts)
Description
This documentation and security-review issue audits every merged PayStream contract entry point for correct Soroban authorization, correct authorized identity, safe check ordering, and intentional public-read exposure.
No production-code change is expected. Any discovered authorization defect must receive a separate high-priority security issue and fix.
Run this audit after the maintainer freezes the Plan Management and Usage-Based Billing features included in scope.
Requirements and Context
Create:
Complete entry-point inventory
Derive the list from the merged
#[contractimpl], generated contract specification, and any additional implementation blocks. Do not rely only on issue descriptions.For every public function record:
require_auth()orrequire_auth_for_args()call;The PR description must contain a concise version of the audit table, and the full table must live in the decision document.
Expected authorization model
Verify against actual merged behavior rather than assuming the following remains correct:
Merchant-authorized operations:
Subscriber-authorized operations:
Administrator-authorized operations:
Intentionally permissionless operations:
charge(), subject to due time, active state, allowance, token approval, and other merged safeguards.Public read operations:
get_plan();get_subscription();get_usage();get_usage_report();Do not assume every function listed above exists. Mark only merged entry points as implemented.
Required attack review
For every mutation, test whether a caller can:
Pay special attention to functions accepting an
Addressargument. Prefer authorization derived from trusted stored state after loading the relevant object, except during safe initialization/creation where the supplied identity itself must authorize.Permissionless charge review
charge()is intentionally callable by anyone. Confirm that this does not grant callers control over:Document potential griefing implications, including repeated catch-up charges for overdue subscriptions, even when transfers are formally authorized. Permissionless does not mean risk-free.
Read-only and privacy review
No-auth reads are expected, but the audit must document what they expose. Do not state that read-only data is non-sensitive merely because it cannot mutate state.
Review exposure of subscriber/merchant addresses, plan terms, due timestamps, usage, pricing, allowance, payment preferences, and version/migration state.
If public exposure conflicts with the final privacy model, open a separate design issue. Do not add ad hoc read authentication in this audit PR.
Soroban auth semantics
Verify conclusions against Soroban SDK
27.0.3and official Stellar/Soroban documentation.Document:
require_auth()versusrequire_auth_for_args();Do not generalize PayStream's historical nested
approve()failure into an unsupported claim about all cross-contract auth.Test evidence
Tests using
env.mock_all_auths()cannot alone prove that the correct identity was required.Where feasible, add or reference focused security tests using explicit mocked auth and authorization-tree assertions to confirm:
If tests exceed documentation-only scope, create a linked test issue with exact cases.
Vulnerability handling
If a missing or incorrect auth check is found:
Suggested Execution
security/require-auth-auditdocs/decisions/auth-audit.mddocs/ARCHITECTURE.mdonly for a discoverability linkdocs(security): audit require_auth usage across contract entry pointsTest and Commit Steps
Only stage
docs/ARCHITECTURE.mdif changed.Guidelines
Closes #<issue-number>.mock_all_auths()as authorization evidence.27.0.3.Complexity
High (200 pts)