StokumNET Threat Model: A Practical STRIDE Analysis
In an ideal world, threat modeling happens before the first line of code. You identify assets, map trust boundaries, enumerate threats, and design countermeasures—all before git init. Textbooks and frameworks prescribe this sequence for good reason: it's cheaper to fix design flaws on a whiteboard than in production.
In reality, many of us build iteratively. Security thinking happens continuously—during architecture decisions, code reviews, and late-night debugging sessions—but the formal documentation often comes later. That's the honest story of this post.
The security principles that shaped StokumNET were present from day one. I chose Go for memory safety. I designed tenant isolation into the data model. I built the infrastructure with zero-trust assumptions. But I never sat down and produced a formal threat model document until now.
This post captures that security thinking in a structured format: a STRIDE-based threat model that documents what we're defending, who might attack it, and how the architecture responds. Whether you're evaluating StokumNET's security posture, learning threat modeling techniques, or facing the same challenge of formalizing security for an existing system—I hope this analysis is useful.
For those unfamiliar with my previous posts: StokumNET Architecture covers the infrastructure design, and the Security Roadmap details planned enhancements. This threat model ties them together with a systematic risk analysis.
The STRIDE Framework
For this analysis, I'm using STRIDE—a threat modeling methodology developed at Microsoft that categorizes threats into six types. It's systematic without being overwhelming, and maps well to the controls we typically implement:
| Category | Description | Question to Ask |
|---|---|---|
| Spoofing | Pretending to be someone else | Can an attacker impersonate a user or system? |
| Tampering | Modifying data or code | Can an attacker alter data in transit or at rest? |
| Repudiation | Denying actions were taken | Can a user deny performing an action? |
| Information Disclosure | Exposing data to unauthorized parties | Can an attacker access data they shouldn't? |
| Denial of Service | Making the system unavailable | Can an attacker disrupt service for legitimate users? |
| Elevation of Privilege | Gaining unauthorized access levels | Can an attacker gain admin rights from a user account? |
System Context
Before analyzing threats, let's establish what we're protecting.
Assets
| Asset | Sensitivity | Impact if Compromised |
|---|---|---|
| Tenant business data (inventory, transactions, suppliers) | High | Competitive intelligence leak, business disruption |
| User credentials | Critical | Account takeover, data breach |
| JWT secrets and encryption keys | Critical | Full system compromise |
| Database credentials | Critical | Direct data access bypassing application controls |
| Source code | Medium | Vulnerability discovery, IP theft |
| Infrastructure configuration | High | System compromise, persistent access |
Trust Boundaries
StokumNET has several distinct trust boundaries where data crosses between security zones:

Data Flow Summary
- User Request → Internet → Edge Server (TLS terminated) → VPN Tunnel → Ingress Controller → Frontend or Backend
- Authentication → Backend validates JWT → Extracts tenant_id → Scopes all queries
- Data Access → Backend → Database (RLS enforces tenant isolation)
- Secrets → Backend → Secrets Manager (runtime secret retrieval)
STRIDE Analysis by Component
Edge Server (Cloud VPS)
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Attacker impersonates legitimate traffic | Spoofing | Medium | TLS with valid certificates, no self-signed | ✅ Implemented |
| Man-in-the-middle on public internet | Tampering | High | TLS 1.2/1.3 only, strong ciphers, HSTS | ✅ Implemented |
| Attacker gains shell access to VPS | Elevation | Critical | SSH key-only auth, brute-force protection, minimal services | ✅ Implemented |
| DDoS attack exhausts resources | DoS | High | Rate limiting, cloud provider DDoS protection | 🔄 Partial |
| Firewall misconfiguration exposes services | Info Disclosure | High | Only ports 80, 443, 22 (restricted) open | ✅ Implemented |
Residual Risk: DDoS protection at the edge is limited to basic rate limiting. A sustained volumetric attack could impact availability. Mitigation: A CDN with DDoS protection is a future consideration for production scale.
Encrypted VPN Tunnel
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Attacker intercepts tunnel traffic | Info Disclosure | Low | Modern cryptographic protocols (Curve25519, ChaCha20-Poly1305) | ✅ Implemented |
| Tunnel endpoint compromise | Elevation | Critical | Endpoints hardened, key rotation procedures | ✅ Implemented |
| Replay attacks on tunnel | Tampering | Low | Built-in replay protection | ✅ Implemented |
| Tunnel availability (ISP issues) | DoS | Medium | Cellular failover on home connection | ✅ Implemented |
Residual Risk: If the edge VPS is compromised, attacker gains tunnel access to private cloud. Mitigation: Defense in depth—application-layer authentication still required.
Ingress Controller
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| TLS certificate expiration | DoS | Medium | Automatic certificate renewal | ✅ Implemented |
| Routing misconfiguration exposes internal services | Info Disclosure | High | Explicit allowlist routing, no default exposure | ✅ Implemented |
| Header injection via upstream | Tampering | Medium | Strict header handling, forwarded header validation | ✅ Implemented |
| Dashboard exposed to internet | Info Disclosure | High | Admin dashboard bound to localhost only | ✅ Implemented |
Frontend (React)
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| XSS via user input | Tampering | High | Framework auto-escaping, no raw HTML injection | ✅ Implemented |
| Sensitive data in client-side code | Info Disclosure | Medium | Only public config vars exposed, no secrets | ✅ Implemented |
| Session hijacking via cookie theft | Spoofing | High | HttpOnly, Secure, SameSite cookies | ✅ Implemented |
| CSRF attacks | Tampering | Medium | SameSite cookies, origin validation | ✅ Implemented |
| Clickjacking | Tampering | Medium | X-Frame-Options header | 📋 Planned |
| CDN/dependency compromise | Tampering | Medium | Subresource Integrity (SRI) | 📋 Planned |
Backend (Go)
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| SQL injection | Tampering | Critical | Parameterized queries only, no string concatenation | ✅ Implemented |
| Broken authentication | Spoofing | Critical | JWT validation on every request, short expiry | ✅ Implemented |
| JWT token theft | Spoofing | High | HttpOnly cookies, token refresh mechanism | ✅ Implemented |
| Tenant data leakage (IDOR) | Info Disclosure | Critical | Tenant ID from JWT, never from request | ✅ Implemented |
| Mass assignment | Tampering | Medium | Explicit field binding, no blind struct mapping | ✅ Implemented |
| Verbose error messages | Info Disclosure | Low | Generic errors to client, detailed logs internally | ✅ Implemented |
| Brute force authentication | Spoofing | High | Rate limiting on login endpoint | ✅ Implemented |
| API abuse / enumeration | Info Disclosure | Medium | Rate limiting, pagination limits | ✅ Implemented |
| User denies performing action | Repudiation | Medium | Activity logging with user context | ✅ Implemented |
Critical Control - Tenant Isolation:
// Every database query MUST include tenant filter
// Tenant ID comes from JWT, never from request parameters
func GetProducts(ctx *Context) {
tenantID := ctx.GetInt("tenant_id") // Extracted from validated JWT
var products []Product
// ✅ CORRECT: Tenant filter always applied
db.Where("tenant_id = ?", tenantID).Find(&products)
// ❌ WRONG: Never trust request parameters for tenant
// requestedTenant := ctx.Query("tenant_id") // VULNERABLE!
}
Non-Repudiation Through Activity Logging:
Every significant action is logged with sufficient context to prove who did what, when:
// Activity log entry structure
type ActivityLog struct {
ID int `json:"id"`
TenantID int `json:"tenant_id"`
UserID int `json:"user_id"`
Action string `json:"action"` // CREATE, UPDATE, DELETE, LOGIN, etc.
Resource string `json:"resource"` // products, transactions, users
ResourceID int `json:"resource_id"`
OldValue *string `json:"old_value"` // JSON of previous state (for updates)
NewValue *string `json:"new_value"` // JSON of new state
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
Timestamp time.Time `json:"timestamp"`
}
// Example: User cannot deny deleting a product
// Log shows: user_id=5 deleted product_id=123 at 2026-01-18T14:30:00Z from IP 192.168.1.100
What gets logged:,
- ✅ All authentication events (login, logout, failed attempts)
- ✅ All data modifications (create, update, delete)
- ✅ Permission changes (role assignments)
- ✅ Export/download of data
- 📋 Planned: Read access to sensitive fields (for compliance scenarios)
Log integrity:
- Logs written to append-only storage
- 📋 Planned: Cryptographic chaining (each entry includes hash of previous)
- 📋 Planned: Forward to tamper-proof centralized SIEM
Database
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Direct database access bypass | Elevation | Critical | No public exposure, network isolation | ✅ Implemented |
| Cross-tenant data access | Info Disclosure | Critical | Row-Level Security (RLS) policies | ✅ Implemented |
| Credential theft from config | Info Disclosure | Critical | Credentials in secrets manager, not env files | ✅ Implemented |
| Backup data exposure | Info Disclosure | High | Encrypted backups, secure storage | 🔄 Partial |
| SQL injection (defense in depth) | Tampering | Critical | RLS as second layer after app validation | ✅ Implemented |
Row-Level Security Policy:
-- Defense in depth: Even if application has a bug, RLS prevents cross-tenant access
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON products
USING (tenant_id = current_setting('app.current_tenant')::int);
-- Application sets tenant context on each connection
SET app.current_tenant = '123'; -- From validated JWT
Secrets Manager
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Secrets manager service compromise | Info Disclosure | Critical | Self-hosted instance, network isolated | ✅ Implemented |
| Service token theft | Elevation | Critical | Token scoped to environment, rotated regularly | ✅ Implemented |
| Secrets logged accidentally | Info Disclosure | Medium | No secrets in application logs | ✅ Implemented |
| Backup includes plaintext secrets | Info Disclosure | High | Encrypted at rest | ✅ Implemented |
Mobile Applications (iOS/Android)
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Token storage on device | Info Disclosure | High | Platform secure storage (Keychain/Keystore) | ✅ Implemented |
| API key in app binary | Info Disclosure | Medium | No embedded secrets, token-based auth only | ✅ Implemented |
| Man-in-the-middle on mobile network | Tampering | High | Certificate pinning considered, TLS enforced | 🔄 TLS only |
| Reverse engineering reveals logic | Info Disclosure | Low | Business logic server-side, app is thin client | ✅ Implemented |
| Jailbreak/root detection bypass | Elevation | Medium | Not implemented—low priority for inventory app | ❌ Accepted Risk |
Tenant Data Lifecycle
Data doesn't just need protection while active—the full lifecycle matters. When a tenant leaves, how do we ensure their data is truly gone? And how do we prove it?
| Threat | Category | Risk | Mitigation | Status |
|---|---|---|---|---|
| Data remnants after tenant deletion | Info Disclosure | High | Secure deletion procedures, cascade deletes | 📋 Planned |
| Tenant disputes deletion occurred | Repudiation | Medium | Deletion audit logs with timestamps | 📋 Planned |
| Backups retain deleted tenant data | Info Disclosure | Medium | Backup retention policy, tenant-aware purge | 📋 Planned |
| Soft-deleted data accessible | Info Disclosure | Medium | Hard delete after grace period, RLS on soft-deleted | 📋 Planned |
Planned Deletion Workflow:
Tenant Requests Deletion
│
▼
┌─────────────────────────┐
│ Grace Period (30 days) │ ← Tenant can cancel, data soft-deleted
│ • Data inaccessible │
│ • RLS blocks all access│
│ • Marked for deletion │
└─────────────────────────┘
│
▼
┌─────────────────────────┐
│ Hard Delete Process │
│ • Cascade delete all │
│ tenant records │
│ • Generate deletion │
│ certificate │
│ • Log with hash proof │
└─────────────────────────┘
│
▼
┌─────────────────────────┐
│ Backup Purge (90 days) │ ← Backups age out naturally
│ • No tenant data in │
│ backups older than │
│ retention period │
└─────────────────────────┘
Deletion Certificate:
To address repudiation concerns, tenant deletion generates a cryptographically signed certificate:
{
"tenant_id": "abc123",
"tenant_name": "Acme Corp",
"deletion_requested": "2026-01-15T10:30:00Z",
"deletion_completed": "2026-02-15T00:00:00Z",
"records_deleted": {
"users": 12,
"products": 1547,
"transactions": 8923,
"companies": 34
},
"certificate_hash": "sha256:a1b2c3...",
"signed_by": "StokumNET Platform"
}
This provides the tenant with proof of deletion for their compliance requirements (GDPR Article 17, CCPA, etc.) and protects the platform from claims that data was retained.
Scenario 1: Malicious Tenant Attempts Cross-Tenant Access
Attacker Profile: Authenticated user from Tenant A attempting to access Tenant B's data.
Attack Vector:
- Attacker examines API requests, notices product IDs in URLs
- Attempts to access
/api/products/12345(belongs to Tenant B) - Modifies request parameters hoping for IDOR vulnerability
Defense Layers:
| Layer | Control | Result |
|---|---|---|
| Application | Tenant ID from JWT, not request | Request scoped to Tenant A |
| Application | Authorization check on resource | 404 or 403 returned |
| Database | Row-Level Security | Even if app bug exists, query returns empty |
Verdict: Attack fails at multiple layers. Defense in depth working as designed.
Scenario 2: Credential Stuffing Attack
Attacker Profile: Automated bot using leaked credentials from other breaches.
Attack Vector:
- Attacker obtains credential lists from dark web
- Attempts automated login with thousands of email/password combinations
- Hopes users reused passwords from breached services
Defense Layers:
| Layer | Control | Result |
|---|---|---|
| Edge | IPS detects pattern, blocks IP | Many attempts blocked |
| Application | Rate limiting (10 attempts/minute/IP) | Slows attack significantly |
| Application | Account lockout after failures | Targeted accounts protected |
| Monitoring | Alert on unusual login patterns | Security team notified |
Verdict: Attack significantly impeded. Improvement: Implement CAPTCHA after N failures, consider WebAuthn/passkeys.
Scenario 3: Compromised Edge Server
Attacker Profile: Sophisticated attacker gains shell access to edge VPS.
Attack Vector:
- Exploits vulnerability in exposed service (SSH, reverse proxy)
- Gains shell access to edge server
- Attempts lateral movement to private cloud
Defense Layers:
| Layer | Control | Result |
|---|---|---|
| Network | VPN tunnel requires cryptographic key, not just network access | Can't traverse tunnel without key |
| Application | JWT validation still required | Can't access API without valid token |
| Data | Database credentials in secrets manager | No plaintext creds on edge server |
| Monitoring | Anomaly detection on access patterns | Unusual traffic patterns alerted |
Potential Impact: Attacker could intercept/modify traffic at TLS termination point. This is the highest-risk compromise scenario.
Mitigations:
- ✅ VPS hardening (minimal services, SSH keys only, brute-force protection)
- ✅ Regular security updates
- 📋 Planned: Host-based intrusion detection
- 📋 Planned: Immutable infrastructure (rebuild vs patch)
Scenario 4: Supply Chain Attack
Attacker Profile: Nation-state or sophisticated criminal compromising package dependencies.
Attack Vector:
- Attacker compromises popular package used by frontend or backend
- Malicious code exfiltrates user data or injects cryptocurrency miner
- Malicious package published, automatically pulled by CI/CD
Defense Layers:
| Layer | Control | Result |
|---|---|---|
| CI/CD | Dependency vulnerability scanning | Known malicious packages flagged |
| CI/CD | Lock files for dependency versions | Prevents surprise updates |
| Build | SBOM generation | Audit trail of what's deployed |
Current Gaps:
- ❌ No dependency proxy (packages pulled directly from public registries)
- ❌ No private registry with approval workflow
Planned Mitigations:
- 📋 Dependency proxy to cache and scan packages
- 📋 SBOM analysis before deployment
- 📋 Signed commits and container images
Scenario 5: Social Engineering / Support Desk Impersonation
Attacker Profile: Social engineer targeting tenant employees or posing as platform support.
Attack Vectors:
Vector A - Targeting Tenant Users:
- Attacker researches company using StokumNET (LinkedIn, company website)
- Sends phishing email mimicking StokumNET login page
- Harvests credentials when user attempts to "log in"
- Uses stolen credentials to access legitimate system
Vector B - Impersonating Support:
- Attacker contacts tenant claiming to be "StokumNET Support"
- Requests password reset, MFA codes, or remote access
- Uses social pressure ("your account will be suspended") to create urgency
- Gains access through manipulation rather than technical exploit
Defense Layers:
| Layer | Control | Result |
|---|---|---|
| Technical | MFA required for all accounts | Stolen password alone insufficient |
| Technical | Login notifications via email | User alerted to suspicious access |
| Process | No password resets via phone/chat | Support cannot be impersonated for this |
| Process | Clear communication channels documented | Users know legitimate contact methods |
| Training | Security awareness for tenant admins | Users recognize social engineering |
Current Gaps:
- ❌ No formal security awareness documentation for tenants
- ❌ No published policy on what support will/won't ask for
- 🔄 MFA available but not enforced for all tenants
Planned Mitigations:
- 📋 Tenant onboarding security guide
- 📋 Published "StokumNET will never ask for..." policy
- 📋 Enforce MFA for all accounts (or strong incentive)
- 📋 Login anomaly detection (new device, new location alerts)
- 📋 Consider WebAuthn/passkeys to eliminate phishable credentials
Risk Summary Matrix
| Risk | Likelihood | Impact | Current Status | Priority |
|---|---|---|---|---|
| Cross-tenant data leakage | Low | Critical | ✅ Mitigated (RLS + app controls) | - |
| Authentication bypass | Low | Critical | ✅ Mitigated (JWT validation) | - |
| SQL injection | Very Low | Critical | ✅ Mitigated (parameterized queries) | - |
| Edge server compromise | Low | High | 🔄 Partially mitigated | High |
| DDoS attack | Medium | Medium | 🔄 Basic rate limiting | Medium |
| Supply chain compromise | Low | High | 🔄 Basic scanning | High |
| Social engineering / phishing | Medium | High | 🔄 MFA available, docs missing | High |
| Insider threat | Low | High | 📋 Limited controls | Medium |
| User action repudiation | Low | Medium | ✅ Activity logging implemented | - |
| Tenant data remnants after deletion | Low | High | 📋 Deletion workflow planned | Medium |
| Backup data exposure | Low | Medium | 🔄 Encrypted at rest | Low |
| Mobile app reverse engineering | Medium | Low | ❌ Accepted risk | - |
Recommendations and Roadmap Alignment
Based on this threat model, here's how the Security Roadmap addresses identified risks:
High Priority (Addresses Critical/High Risks)
| Roadmap Item | Threats Addressed |
|---|---|
| Tamper-proof centralized logging | Edge compromise detection, insider threat, non-repudiation |
| Code and artifact signing | Supply chain attacks |
| Dependency proxy | Supply chain attacks |
| Host-based IDS on edge | Edge compromise detection |
| Tenant security documentation | Social engineering, phishing |
| MFA enforcement | Credential theft, account takeover |
Medium Priority
| Roadmap Item | Threats Addressed |
|---|---|
| CDN with DDoS protection | Denial of service |
| Security headers (CSP, SRI) | XSS, CDN tampering |
| Enhanced rate limiting | Credential stuffing, API abuse |
| Tenant data deletion workflow | Data remnants, compliance (GDPR/CCPA) |
| Login anomaly detection | Social engineering, stolen credentials |
Lower Priority (Already Well-Mitigated)
| Roadmap Item | Threats Addressed |
|---|---|
| Optional E2E encryption | Data exposure (defense in depth) |
| Certificate pinning on mobile | MITM on mobile (already using TLS) |
Conclusion
Formalizing this threat model—even retroactively—proved valuable. It forced me to articulate assumptions that were implicit in the design, identify gaps I hadn't consciously prioritized, and create a document that can evolve as the system grows.
The exercise confirmed that the foundational architecture addresses the most critical threats, particularly multi-tenant data isolation. But it also highlighted areas where my intuitive security decisions need reinforcement with additional controls—especially around the human element (social engineering) and data lifecycle (secure deletion).
The most significant residual risks are:
- Edge server compromise — Mitigated by defense in depth, but monitoring improvements needed
- Supply chain attacks — Basic controls in place, dependency proxy planned
- Social engineering — Technical controls (MFA) exist, but documentation and user awareness gaps remain
- Tenant data lifecycle — Deletion workflow and compliance documentation needed
If you're in a similar position—building something with security in mind but without formal documentation—I'd encourage you to do this exercise. The structure of STRIDE (or PASTA, or attack trees, or whatever framework fits your thinking) transforms scattered security intuitions into a coherent, reviewable, improvable artifact.
Security is iterative. This threat model will evolve as the system grows and the threat landscape changes. The discipline of regularly revisiting these scenarios keeps security decisions grounded in reality rather than compliance theater.
This threat model covers StokumNET as of January 2026. Threat models should be updated when architecture changes significantly, new features are added, or new threat intelligence becomes available.
Related Posts:
Member discussion