STRIDE Framework Implementation: Spoofing, Tampering, Repudiation, Information Disclosure, DoS, and Elevation of Privilege
Operationalizing STRIDE moves security from a theoretical exercise into a set of deterministic engineering controls wired directly into your architecture and pipelines. Each of the six threat categories — Spoofing, Tampering, Repudiation, Information Disclosure, Denial of Service, and Elevation of Privilege — maps to specific attack vectors that, when left unmitigated, enable credential theft, data corruption, audit evasion, sensitive data leakage, service outages, and unauthorized access escalation. This guide is part of Threat Modeling Fundamentals & Methodology, which covers the full lifecycle from system decomposition through risk scoring. The controls here build on rigorous attack surface mapping techniques and depend on precisely modeled trust boundaries.
Threat Anatomy
STRIDE was formalized at Microsoft in the late 1990s as a structured taxonomy for enumerating threats against individual components in a Data Flow Diagram. Its power is that it forces engineers to reason from an attacker’s perspective rather than from a defender’s wishlist.
How each category enables real attacks
| STRIDE Category | Attacker Goal | Representative MITRE ATT&CK Technique |
|---|---|---|
| Spoofing | Impersonate a legitimate identity | T1078 Valid Accounts, T1528 Steal Application Access Token |
| Tampering | Modify data in transit or at rest | T1565 Data Manipulation, T1190 Exploit Public-Facing Application |
| Repudiation | Deny performing a malicious action | T1070 Indicator Removal on Host |
| Information Disclosure | Exfiltrate sensitive data | T1552 Unsecured Credentials, T1041 Exfiltration Over C2 Channel |
| Denial of Service | Exhaust resources and disrupt availability | T1499 Endpoint Denial of Service |
| Elevation of Privilege | Gain capabilities beyond granted authorization | T1548 Abuse Elevation Control Mechanism |
The framework is applied per component and per data flow in your DFD: every process, data store, and external entity receives a STRIDE analysis independently, because the same underlying code can be simultaneously vulnerable to Spoofing at its authentication endpoint and Information Disclosure in its error handling.
MITRE ATT&CK techniques T1078 and T1548 appear most frequently in post-breach analyses of web application compromises, which is why Spoofing and Elevation of Privilege mitigations carry the highest implementation priority in most threat models.
For a concrete application of this analysis to distributed systems, the STRIDE microservices deep-dive covers per-service DFD decomposition and service mesh authorization patterns.
Prerequisites & Scope
Before applying the controls in this guide, the following must be in place:
- A completed Level 1 and Level 2 Data Flow Diagram covering all processes, data stores, external entities, and data flows — including any legacy SOAP/REST adapters and third-party SDKs
- Identified and documented trust boundaries at every zone transition: public internet → API gateway, gateway → internal services, service → database, service → third-party SaaS
- A catalogued attack surface listing all HTTP/gRPC endpoints, WebSocket connections, and message queue topics with their authentication requirements and data classification levels
- A runtime that supports mutual TLS or equivalent cryptographic identity — this is a hard dependency for Spoofing mitigations
- A centralized log aggregation platform (ELK, Splunk, CloudWatch Logs, or equivalent) with at least write-once storage tier available for Repudiation controls
- A CI/CD pipeline (GitHub Actions, GitLab CI, or similar) where policy gates can block merges on control failures
Mitigation Architecture
The diagram below shows the hardened data flow from an external client through an API gateway, internal services, and persistent stores. Trust zones are color-coded: untrusted external zone in red, boundary enforcement nodes in yellow, and trusted internal zone in green. Each zone transition enforces a distinct STRIDE control.
The key architectural insight is that Spoofing and DoS controls must be enforced at the boundary node — the API gateway — before any request reaches internal services. Tampering and Elevation of Privilege controls live in the internal service layer. Repudiation and Information Disclosure controls are storage-layer concerns applied at the data store and log aggregation tier.
Step-by-Step Implementation
Step 1 — Spoofing: Cryptographic Identity Verification (OWASP ASVS V2, NIST AC-3)
Spoofing exploits missing or weak identity verification to impersonate users, services, or API clients. The mitigations below apply at the authentication perimeter and at every internal service-to-service call.
- Enforce mutual TLS (mTLS) for all internal service communication. Terminate external TLS at the API gateway and forward mTLS tokens downstream; do not allow plaintext or one-way-TLS between internal services.
- Issue short-lived JWT/OIDC tokens with
expclaims no greater than 15 minutes. Validateiss,aud,sub, and the cryptographic signature against a rotating JWKS endpoint. Reject any token missing annbfclaim. - Enforce
SameSite=StrictandHttpOnly; Securecookie attributes. Disable all fallback authentication mechanisms.
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({ jwksUri: process.env.AUTH_JWKS_URI! });
export function verifyToken(token: string): Promise<jwt.JwtPayload> {
return new Promise((resolve, reject) => {
jwt.verify(
token,
(header, callback) => {
client.getSigningKey(header.kid, (err, key) => {
if (err) return callback(err);
callback(null, key.getPublicKey());
});
},
{
algorithms: ['RS256'],
issuer: process.env.AUTH_ISSUER,
audience: process.env.AUTH_AUDIENCE,
maxAge: '15m',
},
(err, decoded) => {
if (err) return reject(new Error('Token verification failed'));
resolve(decoded as jwt.JwtPayload);
}
);
});
}
Step 2 — Tampering: Payload Integrity Enforcement (OWASP ASVS V5, NIST SI-7)
Tampering attacks modify data in transit or at rest — injecting malicious payloads into request bodies, corrupting queue messages, or altering stored records. HMAC payload signatures and strict input validation are the primary controls.
- Sign critical request bodies using HMAC-SHA256. Verify signatures before deserialization; reject unsigned payloads at the edge.
- Apply allow-list schemas (JSON Schema, protobuf validation) on all ingress. Reject malformed payloads before they reach business logic.
- Bind all database queries at the driver level. Never concatenate user-supplied input into query strings — see parameterized queries for SQL and NoSQL injection for implementation specifics.
import hmac
import hashlib
import os
from fastapi import Request, HTTPException
SECRET_KEY = os.environ["PAYLOAD_HMAC_SECRET"].encode()
async def verify_payload_integrity(request: Request, body: bytes) -> bool:
signature = request.headers.get("X-Payload-Signature")
if not signature:
raise HTTPException(status_code=401, detail="Missing HMAC signature")
expected = hmac.new(SECRET_KEY, body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(signature, expected):
raise HTTPException(status_code=403, detail="Payload integrity check failed")
return True
Step 3 — Repudiation: Immutable Audit Trails (OWASP ASVS V7, NIST AU-9)
Repudiation threats exploit inadequate or mutable audit trails, allowing malicious actors to deny actions they performed. Defenses require cryptographic log chaining and write-once storage.
- Hash each log entry with SHA-256 and include the previous entry’s hash to create a tamper-evident chain.
- Capture
actor_id,action,resource,timestamp,source_ip, andcorrelation_idin structured JSON or Protobuf format on every write. - Stream logs to immutable object storage (for example, S3 Object Lock in COMPLIANCE mode or GCP Bucket Lock) with a retention policy that satisfies your SOC 2 audit window.
package audit
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"time"
)
type LogEntry struct {
Timestamp time.Time `json:"ts"`
ActorID string `json:"actor_id"`
Action string `json:"action"`
Resource string `json:"resource"`
CorrelationID string `json:"correlation_id"`
PrevHash string `json:"prev_hash"`
}
func NewEntry(actor, action, resource, correlation, prevHash string) LogEntry {
return LogEntry{
Timestamp: time.Now().UTC(),
ActorID: actor,
Action: action,
Resource: resource,
CorrelationID: correlation,
PrevHash: prevHash,
}
}
func (e LogEntry) MarshalAndHash() ([]byte, string) {
data, _ := json.Marshal(e)
hash := sha256.Sum256(data)
return data, hex.EncodeToString(hash[:])
}
Step 4 — Information Disclosure: Data Scoping and Encryption (OWASP ASVS V6, NIST SC-28)
Information Disclosure stems from excessive error verbosity, improper data scoping, and unencrypted sensitive data stores. Controls must be architecturally enforced at the storage and response layers.
- Apply field-level encryption (FLE) at the application layer using envelope encryption: AES-256-GCM for the data, KMS-managed keys for the envelope. Encrypt sensitive PII and PHI before they are written to any store.
- Apply role-based data masking at the query layer. Return
****or truncated values for non-privileged roles; never expose raw PII in list endpoints. - Return generic HTTP status codes with opaque correlation IDs in all error responses. Never expose stack traces, query plans, or internal file paths — see secure HTTP header configuration for response-header hardening that complements this control.
Step 5 — Denial of Service: Resource Protection (OWASP ASVS V13, NIST SC-5)
DoS attacks target resource exhaustion through high-volume requests, oversized payloads, or query amplification. Controls require deterministic rate limits at the gateway and fail-fast circuit breakers at the service layer.
- Implement token-bucket rate limiting with a sliding window algorithm at the API gateway and at service mesh sidecars. Differentiate limits by endpoint criticality and user tier.
- Deploy circuit breakers (Resilience4j, Envoy) to fail fast when downstream latency exceeds configured thresholds, preventing cascading failures.
- Enforce strict
Content-Lengthand JSON depth limits at the reverse proxy. Reject oversized requests before they reach application code.
const { rateLimit } = require('express-rate-limit');
const { RedisStore } = require('rate-limit-redis');
const strictLimiter = rateLimit({
store: new RedisStore({
sendCommand: (...args) => redisClient.sendCommand(args),
}),
windowMs: 15 * 60 * 1000, // 15-minute sliding window
max: 100, // requests per window per key
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Rate limit exceeded. Retry after window expires.' },
keyGenerator: (req) => req.headers['x-forwarded-for']?.split(',')[0] || req.ip,
});
module.exports = strictLimiter;
Step 6 — Elevation of Privilege: Authorization Enforcement (OWASP ASVS V4, NIST AC-6)
Elevation of Privilege attacks exploit insufficient authorization checks to gain capabilities beyond what is granted — horizontal privilege escalation across tenants or vertical escalation from user to admin.
- Define granular permission matrices with RBAC or ABAC. Use a policy engine such as OPA or Cedar to evaluate context-aware access rules at runtime; centralize policy decisions rather than scattering
if (isAdmin)checks across codebases. - Validate authorization tokens on every internal microservice request. Never assume that network isolation implies trust — this is the foundational tenet of zero-trust service-to-service communication.
- Start with deny-all IAM policies. Grant minimum required scopes using the principle of least privilege and audit all scope grants quarterly.
Edge Cases & Bypass Patterns
Spoofing bypass: algorithm confusion attacks on JWT
If the verification code accepts the alg header from the token itself, an attacker can switch a RS256-signed token to HS256 and sign it using the public key as the HMAC secret. Fix: pin the accepted algorithm explicitly in verification options — never derive it from the token header.
Tampering bypass: replay attacks on HMAC-signed payloads
HMAC alone does not prevent replay. An attacker captures a valid signed request and resubmits it. Fix: include a monotonically increasing nonce or a timestamp-bounded replay window in the signed payload and reject payloads with duplicate nonces or timestamps outside a ±60-second window.
Repudiation bypass: log injection via user-controlled fields
If actor_id or resource fields are written to logs without sanitization, an attacker can inject newlines to forge log entries. Fix: sanitize all user-controlled values before writing to the log chain; use structured (non-line-based) log formats such as JSON or Protobuf rather than plain text.
Information Disclosure bypass: verbose error responses in non-production environments
Developers commonly disable generic error handling in staging environments for debugging convenience, but staging environments often share the same secrets or data as production. Fix: enforce the same generic error response middleware in all environments; use correlation IDs and a separate internal error detail endpoint gated by admin authorization.
Elevation of Privilege bypass: IDOR on tenant-scoped resources
A user authenticated to tenant A supplies tenant B’s resource ID in the path parameter and receives a valid response because the authorization check validates the user’s role but not their tenant scope. Fix: always scope resource lookups to the authenticated principal’s tenant; add AND tenant_id = :caller_tenant_id to every data access query. The injection attack prevention controls for parameterized queries apply here as well.
Automated Testing & CI Validation
Unit test: JWT algorithm pinning (TypeScript/Vitest)
import { describe, it, expect } from 'vitest';
import jwt from 'jsonwebtoken';
import { verifyToken } from './auth';
describe('verifyToken — Spoofing controls', () => {
it('rejects tokens signed with HS256 when RS256 is required', async () => {
const maliciousToken = jwt.sign(
{ sub: 'attacker', aud: process.env.AUTH_AUDIENCE },
'any-secret',
{ algorithm: 'HS256' }
);
await expect(verifyToken(maliciousToken)).rejects.toThrow('Token verification failed');
});
it('rejects expired tokens', async () => {
const expired = jwt.sign(
{ sub: 'user', exp: Math.floor(Date.now() / 1000) - 60 },
'secret'
);
await expect(verifyToken(expired)).rejects.toThrow('Token verification failed');
});
});
CI gate: IaC policy scanning and STRIDE control validation
# .github/workflows/stride-ci-gate.yml
name: STRIDE Control Validation
on: [pull_request]
jobs:
stride-controls:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Scan IaC for trust boundary violations
run: |
pip install checkov
checkov -d infrastructure/ \
--check CKV_AWS_19,CKV_AWS_23,CKV_AWS_86 \
--compact --quiet
# CKV_AWS_19: S3 bucket encryption at rest (Information Disclosure)
# CKV_AWS_23: RDS encryption (Information Disclosure)
# CKV_AWS_86: CloudFront logging (Repudiation)
- name: Validate rate limiting configuration
run: |
pip install pyyaml jsonschema
python scripts/validate_rate_limits.py --config config/rate-limits.yaml
- name: OPA policy check — RBAC coverage
run: |
docker run --rm -v $(pwd):/workspace \
openpolicyagent/opa:latest \
eval --data /workspace/policies/ \
--input /workspace/config/service-permissions.json \
'data.authz.all_endpoints_covered'
- name: SAST — detect missing input validation
uses: github/codeql-action/analyze@v3
with:
languages: javascript, python
queries: security-and-quality
Compliance Mapping
| Framework | Control | Satisfied By |
|---|---|---|
| OWASP ASVS V2 | Authentication verification | mTLS, JWKS-validated JWT, exp/aud/iss checks (Step 1) |
| OWASP ASVS V4 | Access control | OPA/Cedar RBAC policy engine, tenant-scoped queries (Step 6) |
| OWASP ASVS V5 | Input validation | Allow-list JSON schema, HMAC payload signatures (Step 2) |
| OWASP ASVS V6 | Cryptography | AES-256-GCM FLE, KMS envelope encryption (Step 4) |
| OWASP ASVS V7 | Error handling and logging | Hash-chained immutable audit logs, opaque error IDs (Steps 3, 4) |
| OWASP ASVS V13 | API and web service | Rate limiting, Content-Length enforcement, circuit breakers (Step 5) |
| SOC 2 CC6.1 | Logical and physical access controls | RBAC matrices, least-privilege IAM, quarterly scope audits (Step 6) |
| SOC 2 CC7.1 | System monitoring | Immutable log retention, structured audit entries with correlation_id (Step 3) |
| NIST SP 800-53 AC-3 | Access enforcement | Authorization token validation on every internal call (Step 1) |
| NIST SP 800-53 AC-6 | Least privilege | Deny-all IAM baseline, minimum scope grants (Step 6) |
| NIST SP 800-53 AU-9 | Protection of audit information | Write-once storage, cryptographic log chaining (Step 3) |
| NIST SP 800-53 SC-5 | Denial of service protection | Token bucket rate limiting, circuit breakers (Step 5) |
| NIST SP 800-53 SC-28 | Protection of information at rest | FLE, KMS key management, role-based masking (Step 4) |
| NIST SP 800-53 SI-7 | Software, firmware, and information integrity | HMAC-SHA256 payload signatures, allow-list validation (Step 2) |
| ISO 27001 A.9 | Access control | mTLS, OIDC/JWT, RBAC (Steps 1, 6) |
| ISO 27001 A.14 | System acquisition and development | SAST/DAST CI gates, IaC policy scanning (CI gate above) |
Common Pitfalls Checklist
Frequently Asked Questions
How does STRIDE implementation differ from traditional vulnerability scanning?
STRIDE focuses on proactive architectural threat identification during the design phase, before code exists. Vulnerability scanning detects known weaknesses in deployed code post-facto. STRIDE implementation means mapping each category to engineering controls and validation gates before the feature ships; scanning confirms that specific known CVEs are absent, but it cannot detect architectural threats like missing Repudiation controls or trust boundary violations.
Can STRIDE controls be automated in a DevSecOps pipeline?
Yes, and they should be. Spoofing controls are validated by checking that authentication is enforced on every route (OPA policy evaluation). Tampering controls are covered by SAST rules that flag missing input validation and by HMAC verification tests. Information Disclosure controls are checked by IaC scanners (Checkov, tfsec) confirming encryption-at-rest configuration. Repudiation controls are validated by confirming log storage uses WORM or Object Lock. DoS controls are confirmed by validating rate limit configuration files against a JSON schema. Elevation of Privilege controls are checked by OPA policies that assert RBAC coverage over every endpoint.
How do you prioritize STRIDE threats across multiple services?
Combine STRIDE categorization with a risk scoring model — see DREAD vs EPSS for threat prioritization for a detailed comparison. Prioritize threats that cross critical trust boundaries, touch regulated data (PII, PHI, PCI scope), or enable lateral movement across a service mesh. Within each category, threats on authentication endpoints and authorization middleware typically rank highest because compromising those paths bypasses all downstream controls simultaneously.
Which STRIDE category is hardest to detect in production?
Repudiation is the most difficult because its absence generates no observable error or alert — the system behaves normally while the audit trail is silently incomplete. Immutable, cryptographically chained log entries are the primary detective control; the only way to verify they are working is to attempt to modify a historical log entry and confirm the chain validation rejects it. Build this assertion into your automated testing suite.
Related
- How to Apply STRIDE to Microservices Architecture — service mesh integration, per-service DFD decomposition, and cross-boundary authorization patterns
- Attack Surface Mapping Techniques — cataloguing every entry point and data flow before STRIDE analysis begins
- Defining Trust Boundaries — mapping zone transitions that each STRIDE category targets
- Threat Prioritization & Risk Scoring — DREAD and EPSS scoring models for ranking STRIDE findings
- Injection Attack Prevention — parameterized queries and input validation controls that satisfy STRIDE Tampering mitigations
- Threat Modeling Fundamentals & Methodology — parent section covering the full threat modeling lifecycle