Build an incident timeline from raw logs
During an incident you have auth logs, web logs and an EDR export, each with its own time zone and format. Apex Flash can merge excerpts into one candidate timeline with source references. You verify the ordering and the claims.
Set it up
- Pull excerpts around the time of interest from each log source and note the time zone of each.
- Add a line number or file name to every excerpt so rows can cite their source.
- Send the excerpts to apex-flash with the timeline prompt.
- Recompute the sort order with a script.
- Check each row against the original line.
- Mark hypotheses separately from facts in your incident notes.
Authorisation boundary
Use this for incidents on systems your organisation owns or investigates under contract, with logs you are permitted to handle. Follow your evidence-handling policy; work on copies.
Sanitised sample input
[auth.log, host web-01, local time UTC]
L112 Oct 8 02:14:09 sshd[2210]: Failed password for deploy from 203.0.113.50 port 51122
L113 Oct 8 02:14:12 sshd[2210]: Failed password for deploy from 203.0.113.50 port 51122
L131 Oct 8 02:31:40 sshd[2305]: Accepted password for deploy from 203.0.113.50 port 51890
[access.log, host web-01, UTC+13]
L8890 09:35:02 POST /admin/upload 200 203.0.113.50
[edr.csv, UTC]
R17 2026-10-08T02:36:11Z web-01 process_start /usr/bin/python3 parent=sshd user=deployThe prompt and the call
Build a timeline from these log excerpts for incident response.
Convert every time to UTC; state the offset you assumed for each source and flag it if unclear.
Output a table: UTC time | source and line id | what happened | confidence.
Then list: gaps or oddities, events that need a second source, and questions for the investigator.
Quote only what is in the logs. Mark inference as "inference".
<logs>
...excerpts...
</logs>import os
from openai import OpenAI
client = OpenAI(base_url="https://wildwestapi.com/v1",
api_key=os.environ["WILDWEST_API_KEY"])
resp = client.chat.completions.create(
model="apex-flash",
temperature=0.2,
messages=[
{"role": "system", "content": "You are a careful incident response assistant."},
{"role": "user", "content": open("timeline_prompt.txt", encoding="utf-8").read()},
],
)
print(resp.choices[0].message.content)Keys look like sk-ww-...; keep yours in the WILDWEST_API_KEY environment variable, never in the script. Calls to /v1/chat/completions use the OpenAI format, billing is pay-as-you-go, and prompts are not retained on /v1.
What to check in the output
- Offsets. The access log above is UTC+13, so 09:35:02 is 20:35:02 UTC the previous day, which does not match 02:xx UTC. A good answer flags this; a poor answer silently merges them. Resolve it from the server configuration, not from the model.
- Row order, by sorting your own parsed timestamps.
- Source ids. Open three random rows and compare.
- Statements of cause. "The brute force succeeded" is a fair reading of the auth lines; "the attacker uploaded a shell" is not supported by a 200 on /admin/upload alone.
Both apex-flash and glm-5.3-flash-cyber are security-tuned models with a 1M-token context window, tool calling and vision. They are not uncensored models, and they are meant for defensive and authorised work like this. The 1M context lets you send large excerpts, but still pre-filter by time window to keep it checkable. Treat the table as a draft for your own timeline tool.
Where this fits
Follow with ATT&CK mapping and use phishing triage if the entry was email. Planning for future incidents is in tabletop exercises. More in DFIR use cases. NIST SP 800-61 Rev. 3 covers incident response recommendations in the CSF 2.0 framework (NIST).
FAQ
Can it parse binary logs such as EVTX?
Convert them to text or CSV first. It works on text you send.
How does it handle conflicting timestamps?
It should flag them if you ask for assumptions in the prompt. Resolve conflicts from system configuration.
Is it admissible as evidence?
No. Treat model output as working notes. The evidence is the original logs.