digininja/DVWA · warning · Exception
Could not decode JSON object.
Error message
Could not decode JSON object.
What it means
After the token decrypts successfully, json_decode($decrypted) returned null, meaning the plaintext was not valid JSON. The expected plaintext is an object like {"user":"example","ex":1723620372,"level":"user","bio":"blah"}; garbage from a bad splice, empty plaintext, or the literal string 'null' all produce a null decode and land here.
Source
Thrown at vulnerabilities/cryptography/source/medium.php:29
$errors = "";
$success = "";
$messages = "";
if ($_SERVER['REQUEST_METHOD'] == "POST") {
try {
if (!array_key_exists ('token', $_POST)) {
throw new Exception ("No token passed");
} else {
$token = $_POST['token'];
if (strlen($token) % 32 != 0) {
throw new Exception ("Token is in wrong format");
} else {
$decrypted = decrypt(hex2bin ($token), $key);
$user = json_decode ($decrypted);
if ($user === null) {
throw new Exception ("Could not decode JSON object.");
}
if ($user->user == "sweep" && $user->ex > time() && $user->level == "admin") {
$success = "Welcome administrator Sweep";
} else {
$messages = "Login successful but not as the right user.";
}
}
}
} catch(Exception $e) {
$errors = $e->getMessage();
}
}
$html = "
<p>
You have managed to get hold of three session tokens for an application you think is using poor cryptography to protect its secrets:
</p>View on GitHub (pinned to 5d5c76cced)
Solutions
- Temporarily var_dump($decrypted) to see the actual plaintext reaching json_decode.
- When splicing ECB blocks, keep whole 16-byte blocks aligned with the field layout of the valid 'Soo' token (its bio field is the attacker-friendly slot).
- Re-encrypt your intended JSON object with the same key/mode and hex-encode it instead of hand-editing.
- Use json_decode with JSON_THROW_ON_ERROR to get the precise syntax error position.
Example fix
// before
$user = json_decode ($decrypted);
if ($user === null) {
throw new Exception ("Could not decode JSON object.");
}
// after
try {
$user = json_decode($decrypted, false, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new Exception("Could not decode JSON object: " . $e->getMessage());
} Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap shape check before json_decode: the documented token format is a JSON object
if (strlen($decrypted) === 0 || $decrypted[0] !== '{') {
throw new Exception('Could not decode JSON object: plaintext is not a JSON object');
} Type guard
function isDecryptedTokenObject(string $plaintext): bool
{
$decoded = json_decode($plaintext);
return $decoded instanceof stdClass
&& isset($decoded->user, $decoded->ex, $decoded->level);
} Try / catch
use JsonException;
try {
$user = json_decode($decrypted, false, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
// JSON_THROW_ON_ERROR distinguishes 'null' input, syntax errors, and depth errors
throw new Exception('Could not decode JSON object: ' . $e->getMessage());
} Prevention
- Use JSON_THROW_ON_ERROR instead of comparing against null - json_decode('null') is also null.
- Inspect the decrypted plaintext (var_dump/log) whenever decode fails; it almost always reveals splice misalignment.
- Validate the decoded object's required fields (user, ex, level) before using them.
When it happens
Trigger: Cut-and-pasting ECB blocks so the reassembled plaintext breaks JSON syntax (unbalanced quotes/braces); a decryption that yields binary garbage whose padding happened to validate; plaintext that is empty or the literal 'null' (json_decode('null') === null, a true false-positive of this check); plaintext produced by encrypting data with a different key that still decrypts to something non-JSON.
Common situations: ECB block-splicing attacks misaligning field boundaries; wrong-key ciphertext that slips past padding checks; token producers serializing with a different format (query string, CSV) than the consumer expects.
Related errors
- Decryption failed
- IV must be 16 bytes, {strlen($iv)} passed
- Decryption failed
- IV must be 12 bytes, {strlen($iv)} passed
- Decryption failed
AI-assisted analysis of digininja/DVWA@5d5c76cced (2026-08-21).
Data as JSON: /api/errors/b4835ca759449762.
Report an issue: GitHub.