Arxiis will not touch a non-local target without a written authorization file. This post is that file, as a template you can use for any penetration test, human or AI-assisted, with notes on why each section exists.

A rules of engagement document does two jobs. It is the legal record that the test was authorized, and it is the operating contract that says what the tester may and may not do. For an AI-assisted test it does a third job: it is a machine-readable input that the system enforces, not just a PDF someone signed.

The template

# authorization.yaml — SCOPE + ROE
engagement_id: e-2041
client:
  legal_entity: "Example Bank Ltd"
  authorizing_officer: "Name, title"          # must have authority to approve testing
  signed_on: "2026-10-20"
  signature_ref: "docusign://..."             # or a scanned letter reference
tester:
  organisation: "Arxiis by Vexoo Labs"
  operator: "Name"                            # the human who supervises the run
  contact_24x7: "+91 ..."

scope:
  in_scope:
    - host: app.example.local
      methods: [web_app]
    - host: api.example.local
      methods: [web_app, api]
    - host: db.example.local
      methods: [service_enum]                 # no exploitation on this host
  out_of_scope:
    - "*.partner.local"                       # third-party systems, no authorization
    - "billing.example.local"                 # production payments, excluded
  environment: staging                        # production | staging | isolated
  data_handling: "No exfiltration of real customer data. Proof limited to a single synthetic record."

window:
  start: "2026-10-21T09:00+05:30"
  end:   "2026-10-23T18:00+05:30"
  blackout: ["2026-10-22T13:00/14:00"]        # e.g. batch jobs

rules:
  rate_limit_rps: 20
  denial_of_service: forbidden
  social_engineering: forbidden
  credential_use: "Only credentials issued for this engagement"
  persistence: forbidden                      # no implants, no scheduled tasks
  exploitation_depth: "Proof of exploit only. No lateral movement without approval."

escalation:
  requires_human_approval: true
  approver: "Client security contact + Arxiis operator"
  examples: ["moving from app tier to data tier", "any action on db.example.local beyond enumeration"]

stop_conditions:
  - "Any out-of-scope host contacted → halt and report"
  - "Service degradation observed → halt and notify"
  - "Time or token budget exhausted → halt and report what is held"
  - "Client calls the 24x7 contact → halt"

budget:
  max_hours: 16
  max_requests_per_host: 50000

evidence:
  retention_days: 90
  ledger: "tamper-evident, hash-chained; shared with client at close"

Why each section exists

Authorizing officer and signature. Without this, the test is unauthorized access. Arxiis's scope guard refuses to start if the authorization block is missing or unsigned. A template that lets you skip this is not a template, it is a liability.

In scope, by host and method. The scope guard checks every outbound request against this list before it leaves. Listing a host with service_enum only means the crew may fingerprint it and nothing more. The check is deterministic; the model cannot talk its way past it.

Out of scope, explicitly. Wildcards matter here. Partner systems, payment rails, and anything you do not own go in this list even if they seem unreachable. The first thing a chained attack does is reach something you thought was unreachable.

Environment and data handling. Staging tests can go deeper than production tests. Say which this is. The data-handling line is what keeps "proof of exploit" from becoming "copied the customer table". Arxiis does not claim data exfiltration in reports, and this line is why: proof stops at one synthetic record.

Window and blackouts. The watchdog enforces the window. Blackouts cover batch jobs, deployments, and anything that would make test traffic look like an incident.

Rules. The rate limit protects the target. The forbidden list is non-negotiable in our template: no denial of service, no social engineering, no persistence. Exploitation depth is the line most AI tools do not have. "Proof of exploit only" means the crew demonstrates the bug and stops.

Escalation. This is the section that makes a test human-supervised rather than self-approving. The crew may find a path from the app tier to the data tier. It may not take it until a named human says yes. The approval and the approver are recorded in the ledger.

Stop conditions. Fail-closed means the default on surprise is to stop. Every condition here produces a partial report with every finding labelled proven or needs review, not a silent abort and not a continuation.

Budget. Time and request limits are the watchdog's inputs. When they are hit, the run ends and reports what it holds.

Evidence. The client gets the ledger, not just the report. Findings can be re-verified against it after the engagement.

Adapting it for a human-led test

Delete the budget block and replace escalation.approver with the lead tester's name. Everything else applies. The sections most human-led engagements leave vague, exploitation depth and stop conditions, are the ones that cause the arguments afterwards.

What the template does not cover

It does not cover legal jurisdiction, data residency, or indemnity. Those belong in the master agreement, not the per-engagement file. It also does not make the test safe on its own. A file is only as good as the system that reads it, and the question to ask any tester, human or AI, is whether these rules are enforced or merely agreed.

Common mistakes in rules of engagement documents

Most disputes after a penetration test trace back to a gap in the rules of engagement. These are the gaps we see most.

A scope written as a network range with no exclusions. A range covers everything inside it, including systems nobody meant to test. List excluded hosts explicitly, even ones that look unreachable.

No named approver for escalation. "The client will be consulted" is not a process. Name a person and a way to reach them during the testing window.

A window with no blackout dates. Batch jobs, deployments and reporting runs all produce traffic that test activity can be confused with. Put them in the document.

An environment that is not stated. Staging and production tolerate different things. Write down which one this is, and what the tester may not do in production.

Data handling left vague. If real customer data is reachable, say what the tester may do with it. For most engagements the answer is: prove access with a single synthetic record, and keep nothing else.

No stop conditions. Decide in advance what makes the test halt: contact with an out-of-scope host, signs of service degradation, a call from your emergency contact. Write them down.

Who signs, and when

A rules of engagement document needs the right people, in the right order.

The client's authorizing officer signs first, because only someone with authority over the systems can grant permission to test them. Legal usually reviews before that signature. The tester's operator signs second, confirming they understand the limits. A technical contact on the client side is named for day-to-day questions and a separate emergency contact for anything urgent.

Keep a dated copy with the engagement record. If the scope changes mid-engagement, amend the document and get the change signed before testing the new target.

Change control during an engagement

Scope often needs to move once testing starts. A developer adds a host, or a team discovers an asset they forgot to list. Handle it with a short process.

  1. The tester or operator raises a written scope-change request naming the host and the reason.
  2. The client's authorizing officer approves or declines in writing.
  3. The change is added to the authorization file and the new version is recorded.
  4. Only then does testing on the new host begin.

For Arxiis, step three is literal. The scope guard reads the updated file, so a host that is not in the current file is out of scope however plausible it looks.

After the engagement

Close-out is part of the rules of engagement, not an afterthought. Agree in advance what happens at the end: when testing credentials are revoked, how the evidence is delivered, how long it is retained, and when test data in the target environment is removed.

A good close-out checklist is short. Credentials revoked. Evidence delivered and its final hash recorded. Retention period confirmed. Test data removed. Report accepted by the client. Each item has a named owner and a date.

Keep the template alive

A template that sits in a folder gets stale. Review it once a year and after any incident that involved a test. Add the questions your own team keeps asking, and remove sections nobody uses.

A one-page version for small engagements

Not every test needs the full file. For a short, low-risk engagement on a single staging application, a one-page version covers the essentials.

Include the client's legal name and the authorizing officer's name and signature. List the exact hosts in scope and any excluded hosts. State the environment, the testing window and any blackouts. Name the technical and emergency contacts. List forbidden techniques. Say who approves anything beyond enumeration. Add the stop conditions and the evidence retention period.

If any of those eight items cannot be filled in, that is a sign the engagement is not ready to start.

Questions to ask before you sign

Before the authorizing officer signs, a few questions are worth asking out loud.

Do we own every host on this list? Is there anything here that belongs to a third party or a cloud provider with its own testing rules? Have the system owners been told? Is there a recent backup of anything the test could affect? And who answers the emergency number at three in the morning?

Five minutes on these questions can save a lot of trouble later.

Cloud and third-party considerations

Applications often depend on services you do not own, such as cloud platforms, payment providers or identity providers. Many of these publish their own rules for security testing, and some require notice or prior approval.

Check the provider's current policy before listing any of their endpoints as in scope. When in doubt, exclude the third-party endpoint explicitly and test your own integration up to the boundary.

Writing the stop conditions well

A stop condition is only useful if someone can tell when it has been met. Prefer measurable triggers to vague ones. "Response times on the test host more than double the normal level for five minutes" is better than "the system seems slow." "Any request to a host not in the scope list" is better than "the tester leaves scope."

For tools that read the file directly, measurable triggers can be enforced by the system itself, rather than depending on someone noticing.

Frequently asked questions

What should a pentest rules of engagement document include?

An authorizing officer and signature, in-scope hosts by method, explicit out-of-scope hosts, environment and data-handling limits, the testing window and blackouts, forbidden techniques, exploitation depth, who approves escalation, stop conditions, budget, and evidence retention.

Does Arxiis run without a rules of engagement file?

No. Arxiis will not engage a non-local target without a written SCOPE + ROE authorization file. The scope guard reads the file and checks every outbound request against it.

What are the most common mistakes in rules of engagement documents?

Scope written as a network range with no exclusions, no named approver for escalation, a window with no blackout dates, an unstated environment, vague data handling, and no stop conditions.

What should happen when scope changes during a pentest?

The tester raises a written change request, the client's authorizing officer approves it in writing, the authorization file is updated and the new version recorded, and only then does testing on the new host begin.

See it on your own stack.

Arxiis runs a coordinated crew of specialist agents through a full engagement in hours, not weeks. Every finding is CVSS-scored, MITRE ATT&CK-tagged and auto-mapped to RBI CSF, CERT-In and nine more frameworks — and every command lands in a tamper-evident ledger. It runs entirely on your own infrastructure.