ModernCS
Session 1.190 minFree preview

Authorization First

Define scope, write rules of engagement, follow coordinated disclosure, and name the laws you can be charged under.

By the end of this session you will be able to:

  • Turn "test our website" into a written scope listing exact hosts, addresses, ports, accounts, and a window
  • Write a one-page rules of engagement document a client can sign, with an out-of-scope list and an emergency stop
  • Find an organization's disclosure channel with /.well-known/security.txt and report a bug you were not hired to find, without becoming the incident

The difference between a security professional and a defendant is a piece of paper, and it has to exist before the first packet, not after the finding. Scope is the control that keeps a test from becoming an intrusion, and almost every "ethical hacker gets arrested" story is about somebody who never wrote it down. Everything else in this course runs against targets you are allowed to touch: a local OWASP Juice Shop, a PortSwigger Web Security Academy lab, a Hack The Box machine. The habits below move you from those to a real client, changing nothing but the paperwork.

Scope is a list of identifiers, not a sentence

"Test our website" is not scope, it is a wish. Scope is enumerable, and if you cannot check a target against it mechanically before running a command, it is not scope yet. Write it as a file next to your notes:

engagement: acme-web-2026-q3
authorized_by: "Layla Mansour, CTO, ACME Ltd"
window:
  start: 2026-09-07T09:00:00+03:00
  end: 2026-09-11T17:00:00+03:00
in_scope:
  hosts:
    - staging.acme.example
    - 198.51.100.16/28
  ports: [80, 443, 8443]
  accounts: [pentest1@acme.example, pentest2@acme.example]
out_of_scope:
  - "*.acme.example other than staging"
  - 198.51.100.32/27   # ACME's ISP range, not ACME
  - third-party SaaS: payment, email, CDN, identity provider
  - denial of service of any kind
  - social engineering of ACME staff
  - customer data: no export, no download, no screenshots of real records

The out-of-scope list is the more useful half. It ends the argument six months later, when the client says they never expected you to touch the partner portal.

Two failures show up constantly. The first is scoping by hostname alone. Hostnames move, so resolve each one at test time and confirm the address is inside your range. staging.acme.example can start pointing mid-engagement at a shared CDN edge nobody in your engagement has spoken to.

The second is the asset the client does not own. It can authorize testing of its own systems, not of its hosting provider, its payment processor, or the range its ISP loaned it. If the target sits on somebody else's infrastructure, read that provider's policy too: separate party, separate permission.

The rules of engagement document

The scope file says what. The rules of engagement, the RoE, says everything else, and it is what gets signed. A workable one fits on a page:

RULES OF ENGAGEMENT - ACME staging web application
 
1. AUTHORIZATION
   Granted by: Layla Mansour, CTO, ACME Ltd
   Confirms ACME owns or controls every asset in scope.yaml.
   Signature: ______________________   Date: __________
 
2. SCOPE
   scope.yaml revision 3. Nothing outside it is tested. Changes
   need written approval from the signer above.
 
3. WINDOW
   2026-09-07 09:00 to 2026-09-11 17:00, Asia/Hebron (UTC+03:00).
 
4. PERMITTED
   Web testing authenticated and not, scanning at no more than 20
   requests per second, exploitation to the minimum depth that
   proves impact.
 
5. FORBIDDEN
   Denial of service, destructive payloads, cracking real password
   hashes, pivoting off scope, exporting production data.
 
6. EVIDENCE
   Encrypted on tester-owned devices, destroyed 90 days after
   report delivery.
 
7. EMERGENCY STOP
   Either party halts by phone; testing stops within 5 minutes.
   Tester +970-XX-XXX-XXXX, ACME +970-XX-XXX-XXXX, both 24h.
 
8. INCIDENT
   Tester-caused outage, or evidence of a prior compromise by
   someone else: testing stops, ACME notified within 30 minutes.

Clause 8 is the one people skip and then need: somebody else's implant on a client machine turns a penetration test into an incident response. Decide in advance who you call.

The signer must have authority to grant it. A developer saying "sure, go ahead" in chat is not authorization, and neither is a purchase order. For bug bounty and disclosure programs the program policy page is the RoE. Its scope table is binding, and testing a domain not listed there is unauthorized however much you meant well.

Coordinated disclosure, and the clock

Sometimes you find a bug in a system nobody hired you to look at, because a URL in your browser bar had an obvious integer. No RoE exists, so you have two jobs: stop, and report.

Stop means stop at proof of existence. One record you can see that is not yours proves broken access control. Ten thousand records is exfiltration, and no jurisdiction cares that you were curious. Do not pivot, do not escalate, keep nothing.

Reporting starts with the channel, which RFC 9116 standardizes at exactly /.well-known/security.txt. Only Contact and Expires are mandatory. Policy, Encryption, Acknowledgments, Preferred-Languages, and Canonical are optional, and Policy is the one to read first: it says what the organization accepts.

With no security.txt, try a security@ address, the vendor's disclosure page, your national CSIRT, or a coordinator such as CERT/CC. Coordinators exist for when a vendor ignores you, and their pressure is a deadline: CERT/CC discloses publicly 45 days after the initial report, whether or not a patch exists. The standards behind this are ISO/IEC 29147, how an organization receives reports, and ISO/IEC 30111, how it handles them internally.

Your report carries the affected asset, the impact in one sentence, minimum reproduction steps, the date found, your proposed disclosure date, and nothing else. Never a demand for payment: attaching a price, outside a published bounty program, is where disclosure becomes extortion.

None of the laws behind this have a curiosity exception. The Computer Fraud and Abuse Act, 18 U.S.C. 1030, in the United States. The Computer Misuse Act 1990 in the United Kingdom, whose section 1 offence is unauthorized access with no damage required. EU Directive 2013/40/EU as each member state implements it. Here, Palestine's 2018 cybercrime decree-law. Read your own jurisdiction's text before you need it: good intent is not a defense to unauthorized access. Authorization is.

Try it

Start a target you are allowed to attack:

docker run --rm -p 3000:3000 bkimminich/juice-shop

Now write the paperwork as if Juice Shop belonged to somebody else. Create scope.yaml and roe.txt from the shapes above: yourself as authorizing party, 127.0.0.1 port 3000 as the only target, a two-hour window with a real timezone offset, four or more out-of-scope entries, and an emergency stop. Then run the disclosure lookup against three organizations whose products you use:

for h in github.com gitlab.com stripe.com; do
  echo "== $h"; curl -sS --max-time 10 "https://$h/.well-known/security.txt"
done

Success condition: your roe.txt names a person with authority, an exact window with a timezone, one in-scope host, four or more out-of-scope entries, and a stop procedure. And for each organization you can say whether it publishes a security.txt, what its Expires date is, and if not, where you would report instead.

Common mistakes

  • Accepting verbal or chat authorization. Asking for a signature feels rude once the client has said yes. The signature is not about trust; whoever investigates you later was not in the room. Get a name, a role, a date, and written confirmation that the client controls every listed asset.
  • Scoping by hostname and never re-resolving. A name that pointed at the client's own server when scope was agreed can point at a shared provider by the time you test. Re-resolve every in-scope name each testing day and check it against your ranges.
  • Proving the bug harder than you have to. Dumping the users table to make a report convincing turns a finding into a breach you caused. One redacted record, one screenshot, one request and response pair. Impact is argued, not harvested.
  • Reporting an out-of-scope finding as a bonus. Saying you also poked at the partner portal tells everyone you tested outside scope, and your report becomes evidence. Report what you observed, then get scope extended in writing before touching anything.

Where this goes next

The next session, Linux for People Who Have Never Used It, puts you on the other side of the paperwork: a shell, and the users, permissions, processes, and logs every finding in this course eventually gets described in terms of. Keep your scope.yaml: this phase's deliverable is a signed rules of engagement document plus a threat model for a lab you did not build.

That was one session of 5 in this phase.

Cybersecurity runs to 4 phases. Buy the whole course, or just the phase you need.