Security

Authentication

All rule management endpoints require a Payability session token and an instance the caller is authorised for. Tracking endpoints are public by design. In front of the app, API Gateway runs the shared PayabilityAPIGatewayAuthorizer, which currently allows every request. The per-endpoint matrix is in REST API.

Cross-origin requests

Browsers may call the API only from https://payability.com and its subdomains (for example crm.payability.com or staging.dev.payability.com). The rule is CORS_ALLOWED_ORIGINS in src/settings.py and applies to every route, including the @cross_origin views. A matching origin is echoed back in Access-Control-Allow-Origin (with Vary: Origin); /track and /tracking also allow credentials, for the pybUserID cookie. Any other origin, plain http, or a look-alike host such as payability.com.example.com gets no CORS headers, so the browser blocks the response.

CORS only restricts browsers. Internal services calling server to server send no Origin header and are not affected; what protects the API from them is the authentication above.

IAM

Each function has its own role. Resources are named exactly, with the environment’s table suffix:

Function Allowed

ApiFunction

CRUD on em_event_rules_v2, em_action_template, em_event_rule_logs_v2; read on em_events; publish to SNS em_events; PutEvents on pyb-notifications; read common/crm

WorkerFunction

CRUD on em_event_rules_v2, em_event_rule_logs_v2; write to em_events; read Kinesis em_events; write to Firehose em_events_es<suffix>; PutEvents on pyb-notifications; read common/crm. The CRM events go to EventLogger over HTTPS and need no IAM permission.

All functions can also write CloudWatch Logs and X-Ray traces.

Secrets

  • Credentials live only in common/crm and are read at runtime. Nothing secret is in the template, samconfig.toml or environment variables.

  • Scripts read tokens and keys from environment variables; none are committed.

  • Tests use fake values set in tests/conftest.py.

Supply chain

  • Dependencies are locked in uv.lock; CI fails if it is out of date with pyproject.toml.

  • The private libraries are pinned to git tags.

  • GitHub Actions are pinned by commit SHA; workflows run with contents: read.

  • The deploy job checks the AWS account ID of its credentials before deploying.