Skip to content

Commit f258166

Browse files
committed
wip OWASP sample
1 parent e1128cb commit f258166

35 files changed

+6345
-218
lines changed

.claude/settings.local.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,13 @@
2424
"Bash(uv add:*)",
2525
"Bash(dir:*)",
2626
"Bash(mkdir:*)",
27-
"Bash(uv run pytest:*)"
27+
"Bash(uv run pytest:*)",
28+
"Bash(del \"c:\\Users\\makara\\Desktop\\full-stack-fastapi-template\\backend\\app\\alembic\\versions\\0e52e71d55df_add_owasp_demo_tables.py\")",
29+
"Bash(ls:*)",
30+
"Bash(npx @tanstack/router-cli generate)",
31+
"Bash(uv run:*)",
32+
"Bash(timeout:*)",
33+
"Bash(npm install:*)"
2834
],
2935
"deny": [],
3036
"ask": []

backend/app/alembic/env.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from app.modules.users.models import User # noqa
2424
from app.modules.items.models import Item # noqa
2525
from app.modules.shortener.models import ShortUrl # noqa
26+
from app.modules.owasp_demo.models import SecretDocument, UserNote, AuditLog # noqa
2627
from app.core.config import settings # noqa
2728

2829
target_metadata = SQLModel.metadata
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""add_owasp_demo_tables
2+
3+
Revision ID: 832f5763b245
4+
Revises: d19595e777a0
5+
Create Date: 2025-12-14 13:28:50.376252
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
import sqlmodel.sql.sqltypes
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision = '832f5763b245'
15+
down_revision = 'd19595e777a0'
16+
branch_labels = None
17+
depends_on = None
18+
19+
20+
def upgrade():
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.create_table('audit_log',
23+
sa.Column('id', sa.Uuid(), nullable=False),
24+
sa.Column('action', sqlmodel.sql.sqltypes.AutoString(length=100), nullable=False),
25+
sa.Column('user_id', sa.Uuid(), nullable=True),
26+
sa.Column('details', sqlmodel.sql.sqltypes.AutoString(length=5000), nullable=True),
27+
sa.Column('ip_address', sqlmodel.sql.sqltypes.AutoString(length=45), nullable=True),
28+
sa.Column('timestamp', sa.DateTime(), nullable=False),
29+
sa.PrimaryKeyConstraint('id')
30+
)
31+
op.create_table('secret_document',
32+
sa.Column('id', sa.Uuid(), nullable=False),
33+
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
34+
sa.Column('content', sqlmodel.sql.sqltypes.AutoString(length=10000), nullable=False),
35+
sa.Column('classification', sqlmodel.sql.sqltypes.AutoString(length=50), nullable=False),
36+
sa.Column('owner_id', sa.Uuid(), nullable=False),
37+
sa.Column('created_at', sa.DateTime(), nullable=False),
38+
sa.ForeignKeyConstraint(['owner_id'], ['user.id'], ondelete='CASCADE'),
39+
sa.PrimaryKeyConstraint('id')
40+
)
41+
op.create_table('user_note',
42+
sa.Column('id', sa.Integer(), nullable=False),
43+
sa.Column('title', sqlmodel.sql.sqltypes.AutoString(length=255), nullable=False),
44+
sa.Column('content', sqlmodel.sql.sqltypes.AutoString(length=5000), nullable=False),
45+
sa.Column('owner_id', sa.Uuid(), nullable=False),
46+
sa.ForeignKeyConstraint(['owner_id'], ['user.id'], ondelete='CASCADE'),
47+
sa.PrimaryKeyConstraint('id')
48+
)
49+
# ### end Alembic commands ###
50+
51+
52+
def downgrade():
53+
# ### commands auto generated by Alembic - please adjust! ###
54+
op.drop_table('user_note')
55+
op.drop_table('secret_document')
56+
op.drop_table('audit_log')
57+
# ### end Alembic commands ###

backend/app/api/router.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from app.core.config import settings
44
from app.modules.auth.routes import router as auth_router
55
from app.modules.items.routes import router as items_router
6+
from app.modules.owasp_demo.routes import router as owasp_demo_router
67
from app.modules.private.routes import router as private_router
78
from app.modules.shortener.routes import router as shortener_router
89
from app.modules.users.routes import router as users_router
@@ -20,3 +21,6 @@
2021
# Include private routes only in local environment
2122
if settings.ENVIRONMENT == "local":
2223
api_router.include_router(private_router)
24+
25+
# OWASP Top 10 Demo - Educational module (local environment only)
26+
api_router.include_router(owasp_demo_router)

backend/app/modules/items/routes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33

44
from fastapi import APIRouter
55

6-
from app.modules.shared import CurrentUser, Message, SessionDep
76
from app.modules.items.schemas import ItemCreate, ItemPublic, ItemsPublic, ItemUpdate
87
from app.modules.items.service import ItemService
8+
from app.modules.shared import CurrentUser, Message, SessionDep
99

1010
router = APIRouter(prefix="/items", tags=["items"])
1111

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""
2+
OWASP Top 10 2025 Vulnerability Demonstration Module
3+
4+
This module provides educational examples of common security vulnerabilities
5+
based on the OWASP Top 10 2025 Release Candidate.
6+
7+
WARNING: These endpoints are intentionally vulnerable for educational purposes.
8+
DO NOT deploy this module in production environments.
9+
10+
OWASP Top 10 2025 RC:
11+
- A01:2025 - Broken Access Control
12+
- A02:2025 - Security Misconfiguration
13+
- A03:2025 - Software Supply Chain Failures
14+
- A04:2025 - Cryptographic Failures
15+
- A05:2025 - Injection
16+
- A06:2025 - Insecure Design
17+
- A07:2025 - Authentication Failures
18+
- A08:2025 - Software or Data Integrity Failures
19+
- A09:2025 - Security Logging and Alerting Failures
20+
- A10:2025 - Mishandling of Exceptional Conditions
21+
"""
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
"""
2+
Models for OWASP demonstration module.
3+
"""
4+
import uuid
5+
from datetime import datetime
6+
from typing import TYPE_CHECKING, Optional
7+
8+
from sqlmodel import Field, Relationship, SQLModel
9+
10+
if TYPE_CHECKING:
11+
from app.modules.users.models import User
12+
13+
14+
class SecretDocument(SQLModel, table=True):
15+
"""
16+
Secret document model - used to demonstrate access control vulnerabilities.
17+
"""
18+
19+
__tablename__ = "secret_document"
20+
21+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
22+
title: str = Field(max_length=255)
23+
content: str = Field(max_length=10000)
24+
classification: str = Field(default="public", max_length=50) # public, internal, confidential, secret
25+
owner_id: uuid.UUID = Field(foreign_key="user.id", nullable=False, ondelete="CASCADE")
26+
owner: Optional["User"] = Relationship()
27+
created_at: datetime = Field(default_factory=datetime.utcnow)
28+
29+
30+
class UserNote(SQLModel, table=True):
31+
"""
32+
User notes - used to demonstrate IDOR vulnerabilities.
33+
"""
34+
35+
__tablename__ = "user_note"
36+
37+
id: int = Field(default=None, primary_key=True) # Sequential ID for IDOR demo
38+
title: str = Field(max_length=255)
39+
content: str = Field(max_length=5000)
40+
owner_id: uuid.UUID = Field(foreign_key="user.id", nullable=False, ondelete="CASCADE")
41+
owner: Optional["User"] = Relationship()
42+
43+
44+
class AuditLog(SQLModel, table=True):
45+
"""
46+
Audit log for demonstrating logging vulnerabilities.
47+
"""
48+
49+
__tablename__ = "audit_log"
50+
51+
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True)
52+
action: str = Field(max_length=100)
53+
user_id: uuid.UUID | None = Field(default=None)
54+
details: str | None = Field(default=None, max_length=5000)
55+
ip_address: str | None = Field(default=None, max_length=45)
56+
timestamp: datetime = Field(default_factory=datetime.utcnow)

0 commit comments

Comments
 (0)