WARNING: THIS APPLICATION IS INTENTIONALLY VULNERABLE. DO NOT DEPLOY TO THE INTERNET. USE FOR LOCAL EDUCATIONAL PURPOSES ONLY.
This lab is a simple E-commerce/Blog application designed to demonstrate common web vulnerabilities (OWASP Top 10) in a controlled, safe environment.
Requirements: Docker and Docker Compose.
-
Start the Lab:
docker compose up --build
-
Access the App: Open http://localhost:5001 in your browser.
-
Reset the Lab: To wipe the database and restore default data:
chmod +x reset_db.sh ./reset_db.sh
- Goal: Bypass authentication without a password.
- Location:
/login - Payload:
admin' OR '1'='1(Put this in the username field, any password). - Fix: Use parameterized queries (prepared statements) instead of string concatenation.
- Bad:
cursor.execute(f"SELECT * FROM users WHERE user='{user}'") - Good:
cursor.execute("SELECT * FROM users WHERE user=?", (user,))
- Bad:
- Reflected XSS:
- Location:
/search - Payload:
<script>alert(1)</script> - Fix: Ensure output encoding/escaping is enabled. In Jinja2, remove
| safe.
- Location:
- Stored XSS:
- Location:
/posts/new(Create a post) - Payload:
<b>Bold</b><script>alert('Stored XSS')</script> - Fix: Sanitize input (e.g., using
bleachlibrary) and escape output.
- Location:
- Goal: View other users' private data.
- Location:
/orders/<id>(Try changing the ID in the URL to see other orders)/profile/<id>(Try changing the ID to see other profiles)
- Fix: Implement access control checks. Ensure the object belongs to the currently logged-in user before showing it.
- Check:
if order.user_id != current_user.id: abort(403)
- Check:
- Goal: Upload a malicious file (e.g., HTML/JS) and execute it.
- Location:
/upload - Payload: Create a file
exploit.htmlwith<script>alert('Upload XSS')</script>and upload it. Click the link to view it. - Fix: Validate file extensions (allowlist), content types, and store files outside the web root or with random filenames. Serve with
Content-Disposition: attachment.
- Goal: Redirect a user to a malicious site.
- Location:
/redirect?next=... - Payload:
/redirect?next=http://google.com - Fix: Validate the
nextparameter against an allowlist of internal paths or domains.
- Goal: Predict the reset token.
- Location:
/reset-password - Analysis: The token is just Base64 encoded
username:timestamp. - Fix: Use cryptographically secure random token generators (e.g.,
secrets.token_urlsafe()).
| Username | Password | Role |
|---|---|---|
| admin | admin123 | Admin |
| alice | alice123 | User |
| bob | bob123 | User |
For educational use only.