Skip to content

security(core): audit require_auth() usage across all functions #47

Description

@Demilade10

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

  1. Freeze and record the source commit included in the audit.
  2. Enumerate entry points from source and generated specification.
  3. Build the intended-versus-actual authorization table.
  4. Review attacker-controlled addresses, stored ownership, check ordering, permissionless charge, public reads, and cross-contract auth.
  5. Gather explicit test evidence or open a linked test issue.
  6. Open separate remediation issues for every mismatch.
  7. 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
  1. 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)

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions