Security

AI Pentesting Prompts That Produce Evidence, Not Just Findings

A practical guide to designing AI-assisted security testing workflows that turn scoped evidence into reviewable findings through structured outputs, validation gates, and controlled execution.

AI Pentesting Prompts That Produce Evidence, Not Just Findings

Thu 23 July 2026

You Ask the Model to Find a Vulnerability

Imagine a new API has landed on your desk. It contains dozens of routes, unfamiliar middleware, and enough code to keep a reviewer busy for days.

Prompt given to the model: “Review this repository and find security vulnerabilities.”

A few moments later, the answer arrives. It mentions SQL injection, hard-coded secrets, missing authorization checks, and unsafe deserialization. It is organized, confident, and formatted like a security report.

Decision point: Would you send it to the engineering team?

Not yet. First determine what the model actually tested. Perhaps no endpoint was traced from request to database. No input reached a dangerous sink. No authorization decision was exercised. No exploitability condition was checked. The output may contain useful hypotheses, but a hypothesis is not yet a finding.

This is where AI-assisted security testing either becomes useful or becomes noise. The challenge is not to make a model sound like a pentester. It is to move from a broad request to a narrow question, from that question to evidence, and from evidence to a result another engineer can reproduce.

Let us rebuild the test one decision at a time.

First, Choose One Question Worth Answering

Among the generated leads is a possible authorization problem in GET /v1/invoices/{id}.

Initial claim: “The endpoint may expose invoices belonging to other users.”

Evidence needed: Identify the resource owner, locate the authorization control, understand the attacker’s access, and observe what happens when one authenticated user requests another account’s invoice.

Test objective: Determine whether an authenticated user can retrieve an invoice owned by a different account through GET /v1/invoices/{id}.

The target has become smaller, but the investigation has become deeper. It now has an interface, an ownership boundary, an attacker capability, and a success condition.

The same shift works across security domains:

Broad request Question the workflow can answer
Check Android intents For the exported activity ShareActivity, can an attacker-controlled extra reach a privileged component without validation?
Look for injection Can the sort query parameter reach a dynamic query operation without safe handling?
Find stored secrets Is the suspected sensitive value written to application storage, and can it be recovered under the stated attacker model?

This is contextual isolation in practice. Instead of dumping an entire repository into the model, provide the route definition, relevant middleware, handler, data-access code, tests, and observed request or response evidence.

Now the model has less material to wander through and one clear question to answer.

Next, Decide What Would Count as Proof

Suppose the model reads the invoice handler and returns:

Initial claim: “The endpoint is vulnerable to IDOR because it fetches an invoice by ID.”

Verdict: Not yet. Fetching an object by ID is normal application behavior. The decisive question is whether ownership or another authorization policy is enforced before the response is returned. That control may exist in middleware, a service layer, a database query, or a policy function outside the visible code.

Before asking for a conclusion, give the task an evidence contract. Require the workflow to return the inspected code path, the attacker capability, the expected authorization control, the validation request and response, and a status of confirmed, needs_validation, or not_reproduced.

Structured output does not make a claim true. It makes missing proof visible.

task:
  id: api-object-authorization-001
  vulnerability_class: broken_object_level_authorization
  target:
    method: GET
    path: /v1/invoices/{id}
    owner_boundary: account_id
  objective: >
    Determine whether an authenticated user can retrieve an invoice that belongs
    to a different account.
  permitted_actions:
    - Read source files listed in context.
    - Inspect supplied test traffic and test fixtures.
    - Generate a test request only against the approved staging target.
  required_evidence:
    - Authorization check location or its absence.
    - Request and response identifiers for the cross-account test.
    - Expected versus observed authorization result.
  output_rules:
    - Do not report a confirmed vulnerability without runtime or test evidence.
    - Return needs_validation when execution is unavailable.
    - Cite every conclusion with an evidence reference.

The contract introduces one rule that should survive every prompt revision:

No evidence, no confirmation.

Then, Let Each Result Choose the Next Step

The model traces the route. It finds authentication middleware and a database query that loads an invoice by its identifier. It still cannot find an ownership condition.

Next decision: Do not generate another explanation. Choose the next test that can reduce uncertainty. The workflow needs a controlled loop:

  1. Plan: identify the smallest question that would reduce uncertainty.
  2. Collect: retrieve the relevant source, fixture, traffic, or approved tool output.
  3. Analyze: connect the evidence to the security control under review.
  4. Validate: replay a request, run a safe test, inspect a trace, or ask for human review.
  5. Decide: confirm the finding, narrow the hypothesis, or stop.

For the invoice endpoint, use two tester-controlled staging accounts. Let Account A create an invoice containing a unique, non-sensitive marker. First confirm that Account A can retrieve it through the tested endpoint. Then authenticate as Account B and request the same identifier.

Validation question: What result would prove the issue?

If Account B receives Account A’s unique marker, the test demonstrates cross-account access—but only if invoices are private and the accounts have no sharing relationship. A denial shows that the tested path enforced the boundary for this case. If the baseline is missing, the response is unclear, sharing is intentional, or the test environment is unavailable, the result remains needs_validation.

The source trace and runtime response answer different questions. The first shows where the control appears to be missing. The second shows how the running system behaves. A reliable workflow keeps both pieces and never substitutes one for the other.

Each loop must change the state of the investigation. If it produces only another version of the same suspicion, the system is generating language rather than testing the target.

Now Apply the Same Method to Other Security Questions

The invoice case gives us one complete path, but an AI pentesting workflow cannot be designed around authorization alone. Let us carry the same reasoning into three different investigations.

An Android Intent Is Only the Beginning

The model finds an exported Android activity named ShareActivity. It also sees an incoming intent extra and a call to startActivity.

Decision point: Is that enough to report intent redirection?

No. The workflow still has to connect the pieces. It should confirm that the component is externally reachable, identify which extras an attacker controls, trace those values to startActivity, startService, or sendBroadcast, and inspect any validation or component restrictions applied before the call.

The next step is a controlled runtime test from a separate application. To confirm intent redirection, the crafted input must make the victim application perform an action that the test application could not invoke directly. For example, it might reach a non-exported internal component or a protected operation.

Opening another exported activity does not prove a security bypass. If the entry activity is not exported, the nested intent is restricted, or no protected effect occurs, narrow the claim or mark it not_reproduced.

The dangerous API was a lead. Reachability, attacker control, and observed behavior determine whether it becomes a finding.

A Query Parameter Is Not Automatically Injection

Next, the model notices that the sort query parameter reaches a query-building function. It labels the path “possible SQL injection.”

Next question: Does the value become part of the SQL command, or does it remain data? An allowlist that maps name or created_at to fixed column names changes the conclusion. Directly inserting the value into the query would justify a safe validation test in the approved environment.

The workflow traces the value from the HTTP handler to the query builder and records any validation or transformation. It then runs paired, non-destructive tests against tester-owned data. To confirm injection, attacker-controlled input must change the query’s behavior while the baseline request remains stable. A database error alone is not enough: malformed input can cause an error without enabling injection. String concatenation without reachable attacker input remains static evidence, not proven exploitation.

A Sensitive Value Must Actually Reach Storage

Finally, the model finds code that writes values to shared preferences, a local database, or a cache. It reports “sensitive data stored insecurely.”

Missing evidence: The workflow must identify the value. A storage API does not prove that passwords, tokens, personal data, or cryptographic material are written through it. Then it must trace the write path or exercise the relevant application flow and inspect the resulting storage under the stated attacker model.

If a tester-owned sensitive value appears on disk, record its location, creation steps, protection, and recovery conditions. Also state whether extraction required a debuggable build, run-as, backup access, root, physical access, or runtime instrumentation.

Data recovered from private storage only after gaining root access does not support the same risk claim as data exposed in externally readable storage. If the evidence shows only a generic storage helper, the claim remains a hypothesis.

These examples use different tools and evidence, but they follow the same progression: narrow the question, trace attacker control, identify the expected control, test safely, and preserve the observed result.

A Lead Becomes a Finding at the Validation Gate

Account A retrieves its marked invoice successfully. Account B, with no sharing relationship, then retrieves the same private marker through the same endpoint. The workflow records both identities, the ownership baseline, requests, responses, code path, and observed cross-account disclosure.

Only now can the lead become a confirmed finding.

Different claims need different gates:

Claim What the workflow must demonstrate
Sensitive value is stored locally Recover a tester-owned value from the stated storage location and document the access prerequisites.
Endpoint lacks object authorization Establish owner access, then demonstrate access by a second tester-controlled principal with no sharing relationship.
User input reaches a dangerous sink Trace attacker control and use paired safe tests to demonstrate the sink’s security-relevant behavior.
Remote code execution Produce a unique, harmless execution marker in an authorized environment; a crash alone is insufficient.

A suspicious API, missing-looking check, unusual endpoint, or dangerous function can guide the next test. None is automatically a report-level vulnerability.

If validation is unavailable: Say so. Needs_validation is more useful than a confident false positive because it tells the reviewer what remains unknown.

Before Giving the Model Tools, Set the Boundaries

The investigation is working, so the temptation is to give the model more access: more tools, more targets, perhaps production credentials.

Safety question: What is the most damaging action this workflow could take if it misunderstood the task or followed malicious content?

“Be careful” is not a security boundary. The execution layer must enforce read-only source access, allowlisted targets, synthetic identities, rate limits, approved staging environments, and human approval before state-changing actions.

Repository files, tickets, web pages, logs, and target responses are untrusted input. They can contain instructions intended to redirect an AI system. Prompt injection and excessive autonomy are therefore system-design risks, not problems solved by clever wording alone.

The model may propose an action. The execution layer decides whether it is permitted.

One Successful Test Is Still Only One Test

Reliability question: Does one successful invoice investigation prove that the prompt architecture is reliable?

No. It proves only that one workflow handled one case.

Build an evaluation set from confirmed vulnerabilities, known false positives, clean components, and incomplete cases where the correct result is needs_validation. Run those cases whenever the model, prompt, tool, context-selection rule, or output schema changes.

Then ask:

  • Did it identify the known issue?
  • Did it attach the correct evidence?
  • Did it reject the known false positive?
  • Did it stop when runtime proof was unavailable?
  • Could a reviewer reproduce the conclusion?

This turns prompt editing into engineering. A change earns its place by improving a measured outcome, not by producing more persuasive prose.

What Would You Trust Now?

Return to the first response: a polished list of possible vulnerabilities generated from a broad repository review.

Now compare it with the invoice investigation. The second result has a bounded target, an attacker model, a code trace, two controlled identities, a captured request and response, an observed authorization failure, and a status that passed a defined validation gate.

Final decision: Which result would you send to the engineering team?

AI can help security teams navigate large codebases, organize evidence, generate focused test plans, and decide what to inspect next. It does not remove the need for a target, a test, a control, or a reviewer.

The objective is not a longer list of possible vulnerabilities. It is a short, defensible path through the target:

Scope → question → evidence → test → observed result → conclusion.

That is the difference between a model that can describe security testing and a workflow that leaves behind something another engineer can replay, challenge, fix, and verify.

References