Skip to content

No authentication on wallet, stamps, pool, and chequebook endpoints #102

@crtahlin

Description

@crtahlin

Description

All gateway endpoints are publicly accessible without any authentication. Sensitive financial endpoints (wallet balance, chequebook, stamp pool) are exposed to anyone who knows the gateway URL.

Reproduction

# Anyone can see the wallet address and balance
curl https://provenance-gateway.dev.datafund.io/api/v1/wallet

# Anyone can see the chequebook balance
curl https://provenance-gateway.dev.datafund.io/api/v1/wallet/chequebook

# Anyone can list all postage stamps (with balances)
curl https://provenance-gateway.dev.datafund.io/api/v1/stamps/

# Anyone can acquire stamps from the pool (costs BZZ)
curl -X POST https://provenance-gateway.dev.datafund.io/api/v1/pool/acquire -d '{"size": "small"}'

# Anyone can purchase new stamps (costs BZZ)
curl -X POST "https://provenance-gateway.dev.datafund.io/api/v1/stamps/purchase?depth=17&amount=10000000"

# Anyone can trigger pool maintenance
curl -X POST https://provenance-gateway.dev.datafund.io/api/v1/pool/maintain

Expected behavior

Sensitive endpoints should require authentication (API key, JWT, or similar). At minimum:

  • Wallet/chequebook: Read-only but exposes financial info — should require auth
  • Stamp purchase/extend: Spends BZZ — must require auth
  • Pool acquire/maintain: Manages shared resources — must require auth
  • Upload: Consumes stamp capacity — should require auth

Actual behavior

All endpoints return data or execute actions for any unauthenticated request.

Impact

  • Financial loss: Anyone can purchase stamps or trigger pool operations, spending the node's BZZ
  • Information disclosure: Wallet address, balance, and stamp inventory exposed publicly
  • Resource abuse: Pool stamps can be acquired and wasted by anyone
  • Stamp exhaustion: An attacker can drain the stamp pool

Suggested fix

Add API key authentication middleware:

from fastapi import Security, HTTPException
from fastapi.security import APIKeyHeader

api_key_header = APIKeyHeader(name="X-API-Key")

async def verify_api_key(api_key: str = Security(api_key_header)):
    if api_key != settings.API_KEY:
        raise HTTPException(status_code=403, detail="Invalid API key")
    return api_key

@app.post("/api/v1/stamps/purchase")
async def purchase_stamp(api_key: str = Security(verify_api_key)):
    ...

Tiered approach:

  • Public (no auth): health check, docs, OpenAPI spec
  • Read (API key): wallet, stamps list, notary info
  • Write (API key + maybe RBAC): purchase, extend, upload, pool operations

Test reference

provenance-smasher/gateway/test_security.py::TestNoAuthDocumented

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingsecuritySecurity vulnerabilities and hardening

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions