Skip to content

Fix REST API multi-target scans returning only the last target's results - #6146

Merged
stamparm merged 1 commit into
sqlmapproject:masterfrom
bharathvemula:fix/2503-api-multitarget-overwrite
Oct 17, 2026
Merged

stamparm merged 1 commit into
sqlmapproject:masterfrom
bharathvemula:fix/2503-api-multitarget-overwrite

Conversation

@bharathvemula

Copy link
Copy Markdown
Contributor

Fixes #2503

Problem

When a single REST API task scans more than one target (crawling with crawlDepth, a -m bulk file, or forms), every target runs through the one StdDbOut instance keyed by the single API taskid. In _storeData(), a COMPLETE write deletes all existing rows for its (taskid, content_type) key before inserting — so each target's TARGET/TECHNIQUES rows silently deleted the previous target's. GET /scan/<taskid>/data ended up returning only the last target's results. This is exactly what #2503 reported for a crawl via sqlmapapi (only test2.php's result came back, its type: 0 entry), and it is the REST API counterpart of #6123, which was fixed for --report-json only.

Fix (mirrors the #6123 approach)

  • lib/controller/controller.py — start() now sets kb.reportTaskId = targetCount per target for API scans too, not just --report-json.
  • lib/utils/api.py — StdDbOut.write() keys a target's data rows as '<taskid>-<n>' when kb.reportTaskId is set (errors/logs still use the plain taskid), and scan_data() folds the per-target rows back into the task's flat {success, data, error} result in target order. Real taskids are dash-less hex, so the '<taskid>-' prefix can only match the task's own rows. Single-target scans keep the exact same response shape.

3 files changed, no changes under thirdparty/ or extra/.

Evidence (local, against current master c94f6d0)

Reproduced end-to-end with a local two-page vulnerable app (identical test.php / test2.php backed by interpolated SQL) scanned as one API task via bulkFile (boolean-based blind, SQLite):

Before — both targets tested and both found injectable (per the scan log), but:

scan data entries: 2
  type=0 (TARGET) value={'url': 'http://localhost:18081/test2.php', ...}
  type=1 (TECHNIQUES) value=[{'place': 'GET', 'parameter': 'username', ...}]
distinct target URLs in results: ['http://localhost:18081/test2.php']

After — 4 entries: TARGET + TECHNIQUES for both targets, in scan order. A single-target API scan of the same app still returns exactly its 2 entries, and a CLI -m + --report-json run still produces the two-target report.

Tests

  • New regression tests in tests/test_api.py: TestStdDbOutMultiTarget (per-target keying; no overwrite) and TestScanDataMultiTarget (route-level merge in target order; other tasks' rows ignored). The multi-target tests fail on unpatched code and pass with this change.
  • python -B -m unittest discover -s tests: 2668 tests, only the 27 pre-existing DNS test errors that also occur on unpatched master in this sandbox (UDP/DNS unavailable); no new failures.
  • python sqlmap.py --smoke-test — PASSED; python sqlmap.py --api-test — PASSED; pyflakes clean on the changed files.

Disclosure: this change was prepared with AI assistance and verified locally as described above.

…lts (sqlmapproject#2503)

A scan covering multiple targets inside a single API task (crawl,
'-m' bulk file, forms) ran every target through one StdDbOut keyed by
the single taskid, so _storeData()'s COMPLETE branch deleted each
earlier target's TARGET/TECHNIQUES rows - /scan/<id>/data returned
only the last target's results.

Mirror the --report-json fix for sqlmapproject#6123: controller.start() now sets
kb.reportTaskId per target for API scans too, StdDbOut.write() keys
data rows '<taskid>-<n>' per target, and scan_data() folds the
per-target rows back into the task's flat result in target order.
Single-target scans keep the exact same response shape.

Regression tests in tests/test_api.py (TestStdDbOutMultiTarget,
TestScanDataMultiTarget).
@stamparm
stamparm merged commit 0cf2f6d into sqlmapproject:master Oct 17, 2026
stamparm added a commit that referenced this pull request Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Only get the last result when crawling using sqlmapapi

2 participants