Last Updated: 2026-02-05
The T402 team takes security seriously. This document outlines our security practices, threat model, and guidelines for secure deployment.
- Reporting Vulnerabilities
- Supported Versions
- Security Architecture
- Cryptographic Primitives
- Threat Model
- Chain-Specific Security
- Deployment Security
- Security Best Practices
- Responsible Disclosure
Please do not report security vulnerabilities through public GitHub issues.
- GitHub Security Advisories (preferred): Report a vulnerability
- Email: security@t402.io
- Type of vulnerability (e.g., signature bypass, replay attack, injection)
- Affected component (SDK, facilitator, specific chain mechanism)
- Steps to reproduce the issue
- Proof-of-concept code (if possible)
- Impact assessment
- Suggested fix (if any)
| Severity | Initial Response | Status Update | Fix Timeline |
|---|---|---|---|
| Critical | 24 hours | 3 days | 7 days |
| High | 48 hours | 7 days | 30 days |
| Medium | 72 hours | 14 days | Next release |
| Low | 7 days | 30 days | Best effort |
| Version | Supported | Notes |
|---|---|---|
| 2.x | Yes | Current stable, actively maintained |
| 1.x | No | Deprecated, no security updates |
T402 is a payment protocol that enables HTTP-based payments using cryptocurrency. The security model relies on:
- Cryptographic signatures for payment authorization
- On-chain verification for settlement finality
- Time-bounded validity to prevent replay attacks
- Server-side verification before resource delivery
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │────▶│ Server │────▶│ Facilitator │
│ (Wallet) │ │ (Resource) │ │ (Settler) │
└─────────────┘ └─────────────┘ └─────────────┘
│ │ │
│ Signs payment │ Verifies sig │ Executes
│ off-chain │ & requirements │ on-chain
└───────────────────┴───────────────────┘
Client Security:
- Private keys never leave the client
- Signatures created locally (browser, mobile, CLI)
- Support for hardware wallets and secure enclaves
Server Security:
- Verifies payment signatures before serving resources
- Validates payment parameters (amount, recipient, deadline)
- Does not hold user funds
Facilitator Security:
- Executes on-chain settlements
- Holds hot wallet for gas fees
- Rate-limited and API key protected
| Component | Algorithm | Standard |
|---|---|---|
| Signature | ECDSA secp256k1 | EIP-712 |
| Authorization | EIP-3009 | TransferWithAuthorization |
| Hashing | Keccak-256 | EIP-191 |
| Nonce | Random 32 bytes | Unique per transaction |
EIP-712 Typed Data:
- Domain separator prevents cross-chain replay
- Structured data prevents signature malleability
- Human-readable signing prompts
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Ed25519 | TON standard |
| Address | SHA-256 + workchain | TON address format |
| Cell Encoding | BOC (Bag of Cells) | TON TL-B |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | ECDSA secp256k1 | TRON standard |
| Address | Base58Check | TRON address format |
| Transaction | Protobuf | TRON protocol |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Ed25519 | Solana standard |
| Address | Base58 | Solana pubkey |
| Transaction | Borsh serialization | Solana protocol |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Ed25519 | NEAR standard |
| Address | Named accounts / implicit | NEAR account model |
| Transaction | Borsh serialization | NEAR protocol |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Ed25519 | Aptos standard |
| Address | Hex (32 bytes) | Aptos account model |
| Transaction | BCS serialization | Move VM |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Ed25519 / secp256k1 / P-256 | Tezos multi-curve |
| Address | tz1/tz2/tz3 (Base58Check) | Tezos address format |
| Token | FA2 (TZIP-12) | Tezos token standard |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | Sr25519 / Ed25519 | Substrate standard |
| Address | SS58 encoding | Polkadot address format |
| Token | Assets Pallet (ID: 1984) | Substrate runtime |
| Component | Algorithm | Standard |
|---|---|---|
| Signature | ECDSA secp256k1 | Bitcoin-compatible |
| Address | C32Check (Crockford base32) | Stacks address format |
| Transaction | Clarity smart contracts | Stacks protocol |
| Threat | Mitigation |
|---|---|
| Replay attacks | Nonces, deadlines, chain-specific domain separators |
| Signature forgery | Industry-standard ECDSA/Ed25519, verified on-chain |
| Man-in-the-middle | HTTPS required, signatures cover all parameters |
| Double spending | On-chain settlement with blockchain finality |
| Insufficient payment | Amount verified before and after settlement |
| Wrong recipient | payTo address included in signed data |
| Expired authorization | Deadline checked on-chain |
| Threat | Responsibility |
|---|---|
| Private key compromise | User/integrator |
| Phishing attacks | User education |
| Smart contract bugs (USDT) | Token issuer (Tether) |
| Blockchain consensus attacks | Blockchain network |
| DNS hijacking | Infrastructure provider |
- Blockchain Security: Underlying blockchains are secure
- Token Contracts: USDT/USDT0 contracts function correctly
- Client Integrity: User's device is not compromised
- TLS/HTTPS: Transport layer is secure
USDT0 (EIP-3009):
// Authorization includes all critical parameters
transferWithAuthorization(
from, // Payer address
to, // Recipient address
value, // Amount in smallest unit
validAfter, // Not valid before this timestamp
validBefore, // Not valid after this timestamp
nonce, // Random 32-byte nonce (replay protection)
v, r, s // ECDSA signature
)Security Considerations:
- Always verify
validBeforeis in the future - Use cryptographically random nonces
- Check return value of transfer
Jetton Transfer:
- Uses comment field for metadata
- Verify sender wallet address matches signed address
- Check query_id for replay protection
Security Considerations:
- Validate workchain ID (0 for basechain)
- Verify Jetton master contract address
- Check sufficient balance before sending
TRC-20 Transfer:
- Standard approve + transferFrom pattern
- Energy/bandwidth considerations
Security Considerations:
- Validate Base58Check address format
- Check contract is official USDT
- Verify sufficient energy for transaction
SPL Token Transfer:
- Associated Token Accounts (ATA)
- Compute unit limits
Security Considerations:
- Validate token mint address
- Check ATA ownership
- Verify transaction simulation before signing
# 1. Use strong, random secrets
export REDIS_PASSWORD=$(openssl rand -hex 32)
export GRAFANA_PASSWORD=$(openssl rand -hex 32)
export API_KEYS="$(openssl rand -hex 32):production"
# 2. Never expose internal services
# Only Caddy (reverse proxy) should be exposed to internet
# 3. Enable API key authentication
export API_KEY_REQUIRED=true- Run containers as non-root
- Use read-only filesystem where possible
- Enable
no-new-privileges - Use internal networks for service communication
- Limit container resources (memory, CPU)
- Scan images for vulnerabilities (Trivy)
- Use specific image tags, not
latest
# docker-compose.prod.yaml security configuration
networks:
internal:
internal: true # No external access
external:
driver: bridge # Only for reverse proxy
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=64M- Minimum Balance: Keep only necessary funds for gas
- Monitoring: Alert on unusual activity
- Rotation: Rotate wallet addresses periodically
- Separation: Use different wallets per environment
- Multi-sig: Consider multi-sig for high-value operations
Default production limits:
- 1000 requests per 60 seconds per IP
- Configurable via
RATE_LIMIT_REQUESTSandRATE_LIMIT_WINDOW
// Good: Load from environment
signer, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("PRIVATE_KEY"))
// Good: Load from secret manager
signer, _ := evmsigners.NewClientSignerFromPrivateKey(vault.GetSecret("evm-key"))
// Bad: Hardcoded
signer, _ := evmsigners.NewClientSignerFromPrivateKey("0x1234...")// Always verify on server before delivering content
result, err := facilitator.Verify(ctx, payloadBytes, requirementsBytes)
if err != nil || !result.IsValid {
return http.StatusPaymentRequired
}
// Settle after delivery (or use escrow pattern)
settleResult, err := facilitator.Settle(ctx, payloadBytes, requirementsBytes)// Validate all parameters match expectations
if (payment.amount < expectedAmount) {
throw new Error("Insufficient payment");
}
if (payment.payTo !== myAddress) {
throw new Error("Wrong recipient");
}
if (payment.deadline < Date.now() / 1000) {
throw new Error("Payment expired");
}- Verify URLs: Ensure you're on the correct domain
- Check Amounts: Review payment details before signing
- Use Hardware Wallets: For high-value transactions
- Monitor Transactions: Set up alerts for wallet activity
- Protocol security review (Trail of Bits, OpenZeppelin, or similar)
- Penetration testing of facilitator service
- Smart contract integration review
- Dependency Scanning: Dependabot, govulncheck, npm audit
- Container Scanning: Trivy in CI/CD pipeline
- SBOM Generation: Software Bill of Materials for each release
- Secret Scanning: GitHub secret scanning enabled
We follow responsible disclosure practices:
- Report: Submit vulnerability privately via channels above
- Acknowledge: We respond within the timeline specified
- Investigate: We confirm and assess the issue
- Fix: We develop and test a fix
- Release: We deploy the fix and publish a security advisory
- Credit: We credit the reporter (unless anonymity requested)
- Security Issues: security@t402.io
- General Support: See SUPPORT.md
- Code of Conduct: See CODE_OF_CONDUCT.md