Skip to content

REST API: /scan/<taskid>/data returns Python repr() strings instead of structured JSON since 1.10 #6054

@gnuletik

Description

@gnuletik

Summary

Since 1.10, the REST API endpoint /scan/<taskid>/data returns a JSON-quoted Python repr() string for value fields where it previously returned a structured JSON object. This breaks any client that parses the documented response shape.

Reproduction

git clone --depth 1 --branch 1.10.4 https://github.com/sqlmapproject/sqlmap.git
cd sqlmap
python3 -c "
import sys; sys.path.insert(0, '.')
from lib.core.convert import stdoutEncode

target = {'url': 'http://example.com/foo', 'query': None, 'data': 'id=1'}
encoded = stdoutEncode(target)
print('input  :', repr(target))
print('output :', repr(encoded))
print('type   :', type(encoded).__name__)
"

Output

1.10.4 (current — broken):

input  : {'url': 'http://example.com/foo', 'query': None, 'data': 'id=1'}
output : "{'url': 'http://example.com/foo', 'query': None, 'data': 'id=1'}"
type   : str

1.9.4 (previous — correct):

input  : {'url': 'http://example.com/foo', 'query': None, 'data': 'id=1'}
output : {'url': 'http://example.com/foo', 'query': None, 'data': 'id=1'}
type   : dict

Why this matters

stdoutEncode is the encoder for the API write path: in lib/core/dump.py Dumper.string()_write()lib/core/common.py dataToStdout()sys.stdout.write(stdoutEncode(clearColors(data)), ...) — where sys.stdout.write is overridden by the API's write() in lib/utils/api.py, which then does jsonize(value).

Concrete impact, called from lib/controller/controller.py:181:

conf.dumper.string("", {"url": conf.url, "query": ..., "data": ...},
                   content_type=CONTENT_TYPE.TARGET)
  • Before: stdoutEncode returned the dict unchanged → jsonize(dict) produced a JSON object → REST clients got "value": {"url": "...", "query": null, "data": "..."}.
  • After: stdoutEncode returns str(dict) (Python repr) → jsonize(string) produces a JSON string → REST clients get "value": "{'url': '...', 'query': None, 'data': '...'}" — unparseable, since None and single-quotes aren't JSON.

For CONTENT_TYPE.TECHNIQUES (type 1) the breakage is worse: the value contains nested dicts with integer keys ({1: {...}, 2: {...}}), so the resulting Python repr is not even convertible to JSON without a Python-literal parser.

Root cause

Commit 09fadc43 ("Minor improvement of stdoutEncode", 2025-12-31) replaced the else: retVal = value branch with elif not isinstance(value, str): value = str(value), eagerly stringifying any non-string input.

Suggested fix

In stdoutEncode, skip the str(value) coercion when conf.api is set (the API path expects to forward structured values to jsonize), or move that coercion out of stdoutEncode and only into the non-API stdout branch in dataToStdout.
Screenshots
If applicable, add screenshots to help explain your problem.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions