How to choose a SQL injection scanner
Yuta Matsuyama
Security Researcher, TECHFUND Inc.
Updated:
Who this is for: Developers and security teams selecting SQL injection testing tools.
Decide where to start testing before choosing a scanner
For example, suppose a value entered into a search form is incorporated directly into an SQL statement. Dynamic testing sends actual requests and looks for problems through differences in responses and other signals. Code analysis traces where values enter the application and which queries they are passed to.
Dynamic testing cannot examine pages or APIs it cannot reach. Code analysis can also miss issues depending on its supported languages and frameworks and how the analysis targets are configured. Even if one approach produces zero findings, that does not mean the other is unnecessary.
Common tools and when to use them
ZAP: An open-source option when you want to check an entire Web application. It has active scan rules for SQL injection and can check for other Web vulnerabilities as well. However, ZAP Baseline performs passive scanning by default, so running it alone does not mean you have completed active testing for SQL injection.
sqlmap: An open-source tool for focused SQL injection testing when you suspect a particular input point. Because it includes automated exploitation features as well as detection, define the scope of permission and use it in an environment where you can limit its impact.
Burp Suite Professional: For testers who want to combine scanning with manual verification while inspecting HTTP requests. The automated scanner is included in paid editions such as Professional, but not in the free Community Edition.
Wapiti: An open-source tool for black-box testing of Web applications from the command line. Its official documentation describes SQL injection testing using errors, Boolean values, and timing differences, as well as API scanning using OpenAPI files. For targets that include SPAs or complex authentication, verify on a case-by-case basis whether it can reach the required paths.
All of these tools send requests to running applications. Alongside the results, record how much of the application they reached, including not only pages but also APIs behind authentication, administration interfaces, and each user's permissions. Combine these tools with source-code-based static analysis as a separate option.
Compare both the number of findings and coverage when evaluating tools
In the same staging environment, set up inputs with known issues and safely parameterized inputs, then compare the results. Check not only whether the tool finds the former, but also whether it incorrectly flags the latter. Also check that testing did not stop midway because authentication expired, and that the tool was able to crawl all necessary entry points, including JSON APIs.
Scanning can affect test data or availability. Obtain explicit permission from the target's owner, agree on the scope, execution time, load, and operations to exclude, and, if possible, test in an environment separate from production.
The MOVEit case: Check publicly accessible paths too
For CVE-2023-34362 in MOVEit Transfer, NVD records that SQL injection could allow an unauthenticated attacker to access the database, and also notes exploitation in May–June 2023. During development, you need to check publicly accessible paths as well as operations performed after login. The following is a fictional educational example using TypeScript and node-postgres, not the MOVEit implementation or code that reproduces this CVE. Limit testing to authorized targets.
After finding an issue, separate values from SQL structure
The basic fix is to pass external values as parameters rather than concatenate them into SQL strings. However, parts of the SQL structure itself, such as sort orders and table names, cannot always be handled through value binding alone. In those cases, choose from fixed options defined by the application.
The following example binds the search value and selects the sort order from two fixed queries. In addition, keep the database user's permissions to the minimum necessary, and separately check that the application user is authorized to view the data. After making the fix, test again to verify both that the original finding has been resolved and that normal searches still work.
import type { Pool } from "pg";
export async function findProducts(
db: Pool, name: string, sort: string,
) {
const queries = {
newest: "SELECT id, name FROM products WHERE name = $1 ORDER BY created_at DESC, id DESC LIMIT 50",
oldest: "SELECT id, name FROM products WHERE name = $1 ORDER BY created_at ASC, id ASC LIMIT 50",
} as const;
if (sort !== "newest" && sort !== "oldest") {
throw new Error("Invalid sort");
}
return db.query(queries[sort], [name]);
}- User enters a search value
- Application binds the value to $1
- Application sends a fixed query and value to the database
Choose SQL structure such as ORDER BY from permitted fixed queries. User authorization and least-privilege database access are separate requirements; this diagram does not guarantee security.
Common questions
Can a scanner guarantee that an application has no SQL injection?
No. Coverage, configuration and test access limit what a scan can find. Combine testing with code review.
Can I test a production application?
Only with explicit authorization and an agreed scope. Dynamic testing may affect data or availability, so use a controlled environment where possible.
Sources and further reading
How Hi AUDIT Agent can help
Use Hi AUDIT Agent to review code data flows, finding locations and suggested fixes. Confirm SQL-injection coverage for your environment and have a person verify the result.
Create a Hi AUDIT Agent account