BugForge - Daily - Shady Oaks Finance
Daily - Shady Oaks Finance
Vulnerabilities Covered
Summary
The Shady Oaks Forecasting feature lets a user attach a caption to a custom indicator result. Rather than returning the caption verbatim, the backend renders it through a server-side template engine before echoing it back, substituting placeholder tokens such as {value} with live server-side data. Because the caption is attacker-controlled and interpolated against the server's own context, supplying a placeholder that names a sensitive variable causes the engine to resolve it and return the secret. The lab hints that an {api_key} variable exists, so injecting {api_key} as the caption leaks the flag directly in the caption field of the JSON response, no privilege escalation or authentication bypass required.
Reference
Application Analysis
Register a new account on the Shady Oaks Finance trading platform and explore the Forecasting feature. The page exposes a Custom indicator panel that lets you build an indicator from price, sma(n), ema(n), min(), max(), avg() and arithmetic. Entering the sample formula (sma(10) + ema(20)) / 2 and clicking Evaluate returns a numeric result of 139.1324.

Noticing an Unexpected Caption in the Response
Capture the underlying Evaluate request to /api/forecast/indicator in Caido. At this point the request only carries the two fields the UI sends, stock_id and formula:
{
"stock_id": 2,
"formula": "(sma(10) + ema(20)) / 2"
}
We weren’t aware a caption field even existed, yet the response comes back with one containing the literal string {value}:
{
"stock": { "id": 2, "symbol": "404EX", "name": "The 404 Exchange" },
"formula": "(sma(10) + ema(20)) / 2",
"value": 139.1324,
"caption": "{value}"
}
That the server returns a caption we never sent is the first clue, and the {value} token is the giveaway: it looks like a template placeholder that the server resolves against its own context, substituting {value} with the computed indicator value. To confirm the field is interpolated server-side rather than returned verbatim, we add our own caption to the payload and see whether it gets rendered too. It does, which confirms a Server-Side Template Injection sink we control.

Injecting the {api_key} Placeholder
Since the caption resolves template variables from the server context, the next step is to probe for sensitive variable names. The lab’s own hint points at an {api_key} variable, which is exactly why we test it here, if the template engine exposes it, naming it in the caption will resolve it straight back to us.
Set the caption to {api_key} and resend the request:
POST /api/forecast/indicator HTTP/1.1
Content-Type: application/json
{
"stock_id": 2,
"formula": "(sma(10) + ema(20)) / 2",
"caption": "{api_key}"
}
The template engine resolves the {api_key} placeholder against the server context and returns the secret in the rendered caption field:
{
"stock": { "id": 2, "symbol": "404EX", "name": "The 404 Exchange" },
"formula": "(sma(10) + ema(20)) / 2",
"value": 139.1324,
"caption": "bug{HYLmfBB7H7A2XLP2BBo56sOYLFTiNyYP}"
}

The flag is disclosed directly in the response, confirming the caption is rendered server-side and leaks arbitrary variables from the template context.
Impact
- Disclosure of sensitive server-side data (an API key) through a user-controlled template field
- A single authenticated request leaks the secret, with no privilege escalation required
- The template context can expose any variable it holds, not just the intended
{value}placeholder - Depending on the engine, template injection can escalate from information disclosure to remote code execution
Vulnerability Classification
- OWASP Top 10: A03:2021 - Injection
- Vulnerability Type: Server-Side Template Injection (SSTI) leading to sensitive data exposure
- Attack Surface: The
captionparameter of the/api/forecast/indicatorendpoint - CWE: CWE-1336 - Improper Neutralization of Special Elements Used in a Template Engine
- CWE: CWE-94 - Improper Control of Generation of Code (‘Code Injection’)
- CWE: CWE-200 - Exposure of Sensitive Information to an Unauthorized Actor
Root Cause
The application takes the user-supplied caption and passes it directly to a server-side template engine, which interpolates placeholder tokens against the server’s own execution context. Because the caption is treated as a template rather than as literal data, any {variable} token the user supplies is resolved server-side. The default caption {value} reveals this behavior, and since the template context also holds sensitive variables such as api_key, an attacker can name them to have their values rendered back into the response.
This vulnerability typically occurs when:
- User input is concatenated into or evaluated as a template string
- The template engine is given access to a context containing secrets or sensitive objects
- No allowlist restricts which placeholders or variables a user-supplied template may reference
Remediation
Never render user input as a template:
- Treat the
captionas inert data and return it verbatim; do not pass user-controlled strings to a template engine - If placeholder substitution is genuinely required, use a fixed, server-side format string and inject only vetted values, rather than rendering the user’s string as the template
Restrict the template context:
- Pass the template engine a minimal, explicitly constructed context that contains only the values intended for display (e.g.
value), never secrets likeapi_key - Maintain a strict allowlist of permitted placeholder names and reject or escape anything outside it
Additional controls:
- Use a logic-less or sandboxed template engine that cannot access arbitrary application variables
- Keep secrets such as API keys out of any object graph that is reachable from rendering code
- Add input validation to reject template metacharacters (
{,},{{,${, etc.) in fields that are never meant to contain them