insecure-design — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited insecure-design (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Guides detection, analysis, and remediation of Insecure Design vulnerabilities — architecture-level failures where security controls are absent or structurally inadequate. Unlike implementation bugs, insecure design cannot be fixed by patching code alone; it requires redesigning the flow or adding missing control layers.
OWASP 2025 position: #6 (down from #4 in 2021, as threat modeling adoption has improved) CWEs covered: 39 | Avg incidence: 1.86% Key CWEs: CWE-434, CWE-269, CWE-362, CWE-799, CWE-602
| Insecure Design (A06) | Implementation Bug (other categories) |
|---|---|
| Rate limiting never architected into login flow | Rate limiter present but misconfigured |
| File upload stored in web root by design | Upload handler missing extension check |
| No tenant isolation in multi-tenant DB schema | Query missing WHERE clause |
| Business logic allows negative quantities | Missing server-side input validation |
A design flaw requires adding a new control or refactoring the architecture, not just patching existing code.
Verify that login, registration, password reset, and high-value transaction endpoints enforce rate limits.
FastAPI — SlowAPI:
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/login")
@limiter.limit("5/minute")
async def login(request: Request, ...): ...Flask — Flask-Limiter:
from flask_limiter import Limiter
limiter = Limiter(app, key_func=get_remote_address)
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login(): ...Red flags to flag in review:
/register, /reset-password, /checkout routes with no rate-limiting decoratorRATELIMIT_ENABLED = False or limiter initialized without being applied to sensitive routes1000/minute on auth endpoints)File uploads must be validated by content, not just extension, and stored outside the web root.
import magic # python-magic
ALLOWED_MIME = {"image/jpeg", "image/png", "application/pdf"}
MAX_SIZE = 5 * 1024 * 1024 # 5 MB
@app.post("/upload")
async def upload(file: UploadFile):
content = await file.read(MAX_SIZE + 1)
if len(content) > MAX_SIZE:
raise HTTPException(400, "File too large")
mime = magic.from_buffer(content[:2048], mime=True)
if mime not in ALLOWED_MIME:
raise HTTPException(400, "Unsupported file type")
# Store in /var/app/uploads/ — NOT inside static/ or public/
safe_path = UPLOAD_DIR / secrets.token_hex(16)
safe_path.write_bytes(content)Red flags:
file.content_type or extension alone (filename.endswith(".jpg"))static/, public/, or any web-accessible pathBusiness logic flaws are application-specific — they exploit valid flows in unintended ways.
Common patterns to test:
| Scenario | Test |
|---|---|
| Negative quantity in cart | POST with quantity: -1, verify order total doesn't go negative |
| Price manipulation | POST with a price field — verify server ignores client-supplied price |
| Concurrent purchase race | Parallel requests to buy last item — verify only one succeeds |
| Booking system abuse | Book same slot twice in parallel |
| Coupon reuse | Apply same coupon twice before first transaction commits |
FastAPI example — safe quantity handling:
class OrderItem(BaseModel):
product_id: int
quantity: int = Field(..., ge=1, le=100) # enforced server-sideRed flags:
ge=1 in Pydantic or equivalentIn multi-tenant apps, every DB query must scope to the authenticated tenant.
Pattern to enforce:
# UNSAFE — returns data across all tenants
def get_reports(db: Session):
return db.query(Report).all()
# SAFE — scoped to current tenant
def get_reports(db: Session, current_user: User):
return db.query(Report).filter(Report.tenant_id == current_user.tenant_id).all()Red flags:
db.query(Model).all() without tenant/user filterSecurity enforced only in the browser is trivially bypassed via direct API calls.
Red flags:
# WRONG — trusting client-supplied role
@app.post("/admin/action")
async def admin_action(role: str = Body(...)): # never do this
if role == "admin":
...
# CORRECT — derive from authenticated token
@app.post("/admin/action")
async def admin_action(current_user: User = Depends(get_current_user)):
if current_user.role != "admin":
raise HTTPException(403)
...Insecure recovery flows are a design flaw, not an implementation bug.
Red flags:
Safe pattern:
# Generate short-lived, single-use, high-entropy token
token = secrets.token_urlsafe(32)
expiry = datetime.utcnow() + timedelta(minutes=30)
# Store hash of token, not the token itself
db_token = PasswordResetToken(
user_id=user.id,
token_hash=hashlib.sha256(token.encode()).hexdigest(),
expires_at=expiry,
used=False
)Use STRIDE to find design flaws before they reach code:
| Threat | Applies to | Example in FastAPI/Flask |
|---|---|---|
| Spoofing | Auth flows | Predictable session tokens, missing MFA |
| Tampering | Data in transit/storage | Missing HMAC on signed data, writable uploads |
| Repudiation | Audit logs | Missing request logging on financial actions |
| Information Disclosure | Error messages, API docs | /docs open in prod, stack traces in 500 |
| Denial of Service | Rate limiting, resource use | No request size cap, missing rate limiter |
| Elevation of Privilege | Authorization design | Client-supplied role, missing tenant scope |
| Finding | Severity | Fix complexity |
|---|---|---|
| No rate limiting on auth/payment endpoints | High | Low — add SlowAPI/Flask-Limiter |
| File uploads stored in web root | High | Medium — move storage path, add serving layer |
| Client-supplied price/role fields | Critical | Low — remove field from request model |
| Missing tenant scope on DB queries | Critical | Medium — audit all queries |
| Knowledge-based security questions | Medium | High — redesign recovery flow |
| Race condition on inventory/booking | Medium | High — add DB-level locking or idempotency |
For deeper dives, see:
references/cwe-details.md — full CWE descriptions and examples for all 39 CWEs in A06references/threat-modeling.md — STRIDE worksheet template for FastAPI/Flask appsFor related OWASP categories that overlap with design issues:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.