tracecathq/tracecat/email-evidence-core

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Load before the first read of any phishing or suspicious email investigation, whether you are triaging a Sublime message group or answering a question about an email in chat. Operating rules for email evidence: which Sublime and Google Workspace reads are permitted, how a mailbox resolves to a person, what each indicator does and does not prove, how to hunt a technique across every mailbox with a Sublime hunt job, and the investigation record you build before you write anything. Load with subli…

Install

npx vskill@latest install tracecathq/tracecat/email-evidence-core

SKILL.md

Email evidence core

Operating rules for the agent that investigates a suspicious email. This skill says where email evidence comes from, what it proves, and how it is worded. It does not say what a case looks like; case-output owns that. It does not say what the triage path is; sublime-phishing-case-lifecycle owns that.

1. The division of work

Sublime is the email security platform. It already analysed the message before you saw it. It parsed the headers, checked SPF, DKIM and DMARC, read the body, extracted and analysed the URLs, examined the attachments, and scored the message with its attack model.

Do not repeat that work. Read its result.

This tenant runs the free Sublime tier. Two consequences hold on every run:

  • The Autonomous Security Analyst does not run here. asa_verdict and asa_dlp_verdict are always null on a message group, and the report endpoints are not available to you. Never wait for an analyst verdict and never describe one. Sublime's own analysis reaches you as the flagged rules and the attack score verdict.
  • Sublime cannot quarantine, release from quarantine, or apply a warning banner. Containment happens in Google Workspace, and a person decides it.

Your work is the part Sublime cannot see:

  • How far the attack reached inside this tenant.
  • Who the recipient is, and how much a compromise of that person would cost.
  • Whether the recipient acted on the message, and whether the account then behaved abnormally.
  • What the evidence supports, written for a person who must decide.

2. Permitted reads

2.1 Sublime, read only
ToolUse it for
tools.sublime.get_message_groupThe full record of one message group. Call it with the canonical ID even when a prompt already holds the group, so you work from the current record.
tools.sublime.analyze_message_by_idThe message's own parsed fields, selected by MQL query. This is your main indicator source. See 2.1.1.
tools.sublime.get_message_data_modelThe whole parsed message in one call. Use it only when you need many fields at once; prefer the MQL route, which returns what you asked for and nothing else. Pass remove_large_text_fields: true.
tools.sublime.list_message_groupsGroups in a time window, or groups matching one indicator.
tools.sublime.search_message_groupsThe same, with query parameters, for campaign scope.
tools.sublime.get_message_group_siem_summaryAttachment hashes, link clicks and source IPs across flagged groups. It cannot be scoped to one canonical ID and it returns tens of thousands of characters, so prefer MQL for one message and use this only for a tenant-wide indicator sweep.
tools.sublime.get_messageThe group membership and delivery record of one message. It carries no body, headers, links or attachments.
tools.sublime.list_user_reportsWhat people reported, and who reported it. Bound it with reported_at_gte.
tools.sublime.get_ruleWhat a flagged rule actually detects, when its name is not enough.
tools.sublime.analyze_urlSublime's link analysis for one URL.

Two endpoints are often unavailable, and they are not in your tool list. Do not ask for them and do not plan a step around them:

  • get_message_eml, the raw message, returns 403 Message access justification required.
  • retrieve_asa_report and retrieve_asa_verdict return 403 and 404, because the Autonomous Security Analyst is an Enterprise feature.

The parsed message is not gated. The justification gate is on the raw artefact only, so the data you need reaches you through 2.1.1.

2.1.1 Reading indicators with MQL

analyze_message_by_id takes a Sublime message ID, not a group ID, and a payload holding a queries list. Each query names one MQL source. Ask for several in one call.

yaml
id: <sublime message id>
payload:
queries:
- source: headers.message_id
- source: sender
- source: recipients
- source: subject
- source: body.links
- source: attachments
- source: headers.auth_summary
- source: headers.hops

What each one gives you:

  • headers.message_id — the original Message-ID, such as <GjdTFq4uSCGPS5uMnDacpg@geopod-ismtpd-3>. Always read this. It is the only exact handle on the message in Google Workspace, and a person needs it to find and quarantine the mail. Put it in the case.
  • sender — the address split into local part, domain, root domain, subdomain and TLD, with the display name.
  • body.links — every link, each with display_url, href_url, display_text, visible, and Sublime's own mismatched flag. A mismatched: true link is the display text disagreeing with the destination. Report that flag; it is Sublime's finding, not yours.
  • attachments — the files, with their hashes and identified types. A null result means the message had none, which is a finding, not a failure.
  • headers.auth_summary — DMARC and SPF with a verdict, a policy and the sending IP. Read section 4 before you report it.

MQL has no [] projection. body.links[].href_url.domain.root_domain fails to parse. Select the collection and read the fields you want from the result.

2.2 Google Workspace, read only
ToolUse it for
tools.google_directory.get_userThe recipient's account state: suspended or active, admin role, org unit, 2-Step Verification.
tools.google_directory.list_tokens, get_tokenThe OAuth apps that person has granted, and their scopes.
tools.google_reports.list_activitiesThe audit log.

Audit log applications, and the question each one answers:

  • login — did this account sign in from an address or a place it has not used before, and were there failed attempts?
  • token — did this account grant a new OAuth app after the message arrived?
  • drive — did this account share something unusually widely after the message arrived?
  • admin — did anything change in the account's configuration, its recovery details or its 2-Step Verification?
  • user_accounts — did the person change their own password or recovery options?

Always bound a list_activities call by time. The window starts at the message delivery time and ends now. A wider window returns noise you will then have to explain.

You hold no Gmail tool. You cannot read a mailbox, and you cannot label, trash or quarantine a message. Those belong to the workflow and to the person who decides.

2.3 Enrichment

VirusTotal, AbuseIPDB and urlscan are available for a URL, a domain, an address or a file hash. Before you call one, check whether Sublime already answered the same question. Sublime's link analysis usually makes a public lookup unnecessary.

Two enrichment calls are not optional on a malicious or suspicious verdict. Make both every time, and put both results in the indicator table:

  1. tools.virustotal.lookup_domain on the sender's registered domain. Read the detection count and the registration date, because a domain registered hours before delivery is the finding, and a zero detection count on a new domain proves nothing.
  2. tools.abuseipdb.lookup_ip_address on the sending IP from headers.auth_summary. A message with no links and no attachments still has a sending IP, and on such a message it is often the only infrastructure indicator you hold. Writing "not enriched" in the indicator table is a gap you chose, not a limit of the tenant.

When either call fails, say which one failed and what you therefore could not establish. Never leave an indicator row saying the value was not looked up when you held the tool to look it up.

Never submit a file or a full URL with a query string to a public service. A phishing URL often carries a token that identifies the recipient, and an attachment can hold company data. Submit a domain or a hash.

Never call `tools.urlscan.lookup_url` on a live phishing investigation. It submits a new public scan. That is a disclosure, not a lookup: the operator of a targeted attack can see that their link was scanned, the result may be public, and each submission makes the run wait while the scan completes. You hold no passive urlscan search tool, so there is no safe urlscan route. Use these in this order instead:

  1. tools.sublime.analyze_url — Sublime's own link analysis. Private to this tenant, and it has already seen the message.
  2. tools.virustotal.lookup_domain on the link's registered domain — a read of what VirusTotal already holds, not a submission.

A link-tracking or shortener domain tells you about the sending platform, not the destination. Report it as such and do not follow it.

When those leave the question open, say so in the case and name a urlscan submission as the next step a person can authorise. Never submit one yourself.

This rule binds you, not the person. It forbids you from making the disclosure on your own initiative. It does not forbid the disclosure from happening. When a workflow offers a person a button that submits the links, that button is the sanctioned route: a named approver reads the warning and takes the decision. Never withhold or omit such a control on the grounds that scanning is forbidden, and never argue a person out of using it. Your job is to make the cost of the choice clear, which is that the submission is public and the sender can see it, and then let them choose.

2.4 Hunting across every mailbox

Everything in 2.1 reads mail that Sublime flagged. A hunt job reads all mail in the window, flagged or not. That difference is the point. A campaign that changed one word to get past a rule does not appear in search_message_groups, and it does appear in a hunt.

Run a hunt on every malicious verdict. This is required work, not an extra.

ToolUse it for
tools.sublime.start_hunt_jobStart the hunt. It returns a job id.
tools.sublime.get_hunt_jobThe job status, with results_truncated and error.
tools.sublime.get_hunt_job_resultsThe findings: message_groups and total_group_count.

Set base_url to https://platform.sublime.security on each of these three calls. If you omit it, the call fails with UnsupportedProtocol: Request URL is missing an 'http://' or 'https://' protocol. That message does not name the cause, so do not try to diagnose it. Add the base_url and call again.

2.4.1 Hunt the technique, not the indicator

This single rule decides whether the hunt finds anything new.

An indicator hunt repeats work you have already done. The sender address, the exact subject and the link domain all point at messages Sublime has already grouped for you. Such a hunt returns the campaign you can already see.

A technique hunt describes the attacker's method. It finds the messages that use the same method with different indicators, which is the part nobody has seen yet.

Work from what made the message malicious, then write MQL for that behaviour:

What made it maliciousHunt for
The display name impersonates an employeeInbound mail whose display name holds an employee name, from a sender domain that is not ours
The sender domain is new and looks like oursInbound mail from a domain that resembles our domain by a character pattern
A credential page behind a linkInbound mail that carries a link to a login or verification path
An invoice or payment change requestInbound mail whose subject holds payment language, from a sender outside our domains
Hunt the variants, not only the form you saw

This is the single most common way a hunt comes back empty when a gap exists. You saw one message, so you write MQL for exactly that message's shape, and you find only the messages that already looked identical. Those are the ones the platform had already flagged, so the hunt tells you nothing new and you wrongly conclude there is no gap.

An attacker varies the lure. Your MQL must allow for the variation:

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
3,853
Repository forks
436
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/tracecathq/tracecat/email-evidence-core/badge)](https://verified-skill.com/skills/tracecathq/tracecat/email-evidence-core)

Something wrong with this skill or its page? Tell us.