Development Pipeline Credential Abuse and Injection
An adversary has compromised developer credentials to harvest sensitive repository secrets and inject malicious code into private source code repositories, bypassing standard CI/CD protections.
Based on research by ESET Research 2026-10-29 9 steps · 3 queries T1078 T1195 T1555
Brief
Why this hunt
The ESET APT Activity Report Q2 2026–Q3 2026 details how North Korea-aligned threat actors target developer environments. These groups compromise identity providers or harvest local credentials to gain access to private source code. Once inside, they move quickly to extract repository secrets and inject malicious code into the supply chain.
Identifying the Push
The hunt begins by examining the GitHub audit log for push events and repository updates. This first query provides a broad list of activity across critical repositories. Because developers push code every day, this step produces many results. The hunt filters these by repository importance and lookback periods to establish a working set of actors and modified resources.
Correlating Secrets and Identity
The second phase runs two queries in parallel to find evidence of account misuse. One query calculates the prevalence of secret enumeration. It stacks API calls like get secret or list keys to find developers who rarely perform these actions. A legitimate developer might occasionally check a secret, but an adversary harvests them systematically. Simultaneously, the hunt checks authentication telemetry from Entra ID, Okta, or GitHub for high-risk sign-ins or failed MFA attempts associated with the same accounts.
Triage and Mitigation
An analyst weighs the combined evidence. A developer who pushed code shortly after a high-risk login and a rare secret enumeration session represents a confirmed compromise. If the verdict is malicious, the playbook directs the operator to revoke all active sessions and Personal Access Tokens for that account. Finally, the hunt concludes with a manual review of the specific code diffs, as audit logs do not capture the actual code changes.
Blind Spots
This hunt relies on audit logs, which have inherent limits. The GitHub API logs the fact that a push occurred but does not include the file diff itself. An analyst must manually inspect the repository to see what code changed. Additionally, sophisticated session hijacking may appear as a successful login. If an actor steals a valid session cookie, the authentication logs may not show a high-risk event or an MFA failure.
How to Run the Hunt
This hunt is an open hunt.md playbook. You can import it directly into Huntbase or any runtime that supports the hunt.md format. It uses standard SQL queries against common cloud and identity surfaces. Focus the initial parameters on your most sensitive production repositories to reduce the initial triage volume.
In this series
Steps
-
Detect unauthorized pushes and repository updates
Query · detection candidateDetect unauthorized pushes or commits to source code repositories.
reads hb_cloud_api_activitysqlSELECT actor_user_name, resource_name, src_endpoint_ip, api_operation, user_agent, time FROM hb_cloud_api_activity WHERE provider = 'github' AND activity_id = 3 AND (LOWER(api_operation) LIKE '%push%' OR LOWER(api_operation) LIKE '%update%' OR LOWER(api_operation) LIKE '%commit%') AND ('{{target_repos}}' = '' OR instr(',' || '{{target_repos}}' || ',', ',' || resource_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. Push events from developer accounts, particularly those associated with critical production repositories. Silence suggests no modifications were logged via the GitHub API.
-
Prevalence of secret enumeration
Query · baselineIdentify if the actors were reading repository secrets, highlighting users who perform these operations rarely.
reads hb_cloud_api_activitysqlSELECT LOWER(api_operation) AS operation, COUNT(DISTINCT actor_user_name) AS users, COUNT(*) AS calls, MIN(time) AS first_seen FROM hb_cloud_api_activity WHERE provider = 'github' AND activity_id = 2 AND (LOWER(api_operation) LIKE '%secret%' OR LOWER(api_operation) LIKE '%key%' OR LOWER(api_operation) LIKE '%token%') AND ('{{scope_actors}}' = '' OR instr(',' || '{{scope_actors}}' || ',', ',' || actor_user_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY operation HAVING users <= 3 ORDER BY users ASCWhat a hit looks like. Developers reading repository secrets outside of standard automated patterns. Silence suggests no rare secret harvesting was detected.
-
High-risk authentication context
Query · enrichmentCheck for sign-in anomalies such as high risk levels or unusual source IPs for the actors in question.
reads hb_auth_signinsqlSELECT actor_user_name, src_endpoint_ip, src_location_country, risk_state, status, time FROM hb_auth_signin WHERE provider IN ('github', 'azure_ad', 'okta') AND (risk_state != 'none' OR status != 'Success') AND ('{{scope_actors}}' = '' OR instr(',' || '{{scope_actors}}' || ',', ',' || actor_user_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')What a hit looks like. A sign-in with an 'atRisk' state or a failed authentication attempt preceding the push activity. Silence means no anomalous logins were detected.
-
Triage session compromise
Agent triageWeigh the evidence from push events, secret access, and auth logs.
-
Route on verdict
DecisionDirect the hunt based on the agent triage.
-
Revoke developer sessions
Response actionImmediately stop the actor by revoking sessions and tokens.
-
Manual commit and diff review
Analyst taskVerify the content of the commits to determine if malicious code was successfully injected.
-
Record remediation and findings
Analyst taskDocument findings and determine if the lead query should be promoted.
Coverage
Scenario coverage
| Stage | Covered | How, or why not |
|---|---|---|
| Developer Credential Harvesting T1555 |
Yes | secret-access-prevalence, high-risk-authentication |
| Source Code Injection T1195 |
Yes | github-push-events, manual-commit-review |
| MDaemon Mail Server Exploitation T1190 |
Out of scope | Belongs to another part of the 'ESET APT Activity Report Q2 2026–Q3 2026' series. |
| Recruitment-Themed Phishing T1566 |
Out of scope | Belongs to another part of the 'ESET APT Activity Report Q2 2026–Q3 2026' series. |
| Backdoor Execution T1059 |
Out of scope | Belongs to another part of the 'ESET APT Activity Report Q2 2026–Q3 2026' series. |
| AI Guardrail Evasion Decoy T1027 |
Out of scope | Belongs to another part of the 'ESET APT Activity Report Q2 2026–Q3 2026' series. |
Blind spots
- Needs direct repository audit of file diffs. The GitHub audit log confirms a push occurred but does not contain the code diff itself, requiring manual inspection. It would answer what specific lines of code were modified.
- Needs hb_auth_signin mfa result detail. Sophisticated session hijacking may appear as a successful login without explicit MFA failure logs. It would answer whether the actor bypassed MFA or used a session cookie hijack.
Parameters & data
Parameters
| Parameter | Type | Default | What it is |
|---|---|---|---|
lookback_days | number | 14 | Days of history to examine. |
scope_actors | list[string] | — | Developer accounts identified in the lead query to pivot on. |
target_repos | list[string] | — | Critical repositories to focus on; empty means all. |
Telemetry
| Source | Category | Telemetry |
|---|---|---|
| Endpoint telemetry (hb_ surfaces) | endpoint | endpoint |
| Identity / sign-in telemetry | identity | identity |
Source
---
analysis: A simple alert on a GitHub push is too noisy; this hunt correlates push
activity with rare secret enumeration and high-risk sign-in context across two telemetry
surfaces (GitHub API and Entra/Okta auth), using stack-counting to isolate anomalous
developer behavior.
blind_spots:
- id: limited-diff-visibility
question: what specific lines of code were modified
requires: direct repository audit of file diffs
risk: The GitHub audit log confirms a push occurred but does not contain the code
diff itself, requiring manual inspection.
stage: initial-access-supply-chain-injection
- id: mfa-bypass-visibility
question: whether the actor bypassed MFA or used a session cookie hijack
requires: hb_auth_signin mfa result detail
risk: Sophisticated session hijacking may appear as a successful login without explicit
MFA failure logs.
stage: credential-access-developer-harvesting
coverage:
- stage: credential-access-developer-harvesting
status: covered
steps:
- secret-access-prevalence
- high-risk-authentication
- stage: initial-access-supply-chain-injection
status: covered
steps:
- github-push-events
- manual-commit-review
- reason: "Belongs to another part of the 'ESET APT Activity Report Q2 2026\u2013\
Q3 2026' series."
stage: initial-access-mdaemon-exploit
status: out_of_scope
- reason: "Belongs to another part of the 'ESET APT Activity Report Q2 2026\u2013\
Q3 2026' series."
stage: initial-access-recruitment-phishing
status: out_of_scope
- reason: "Belongs to another part of the 'ESET APT Activity Report Q2 2026\u2013\
Q3 2026' series."
stage: execution-backdoor-deployment
status: out_of_scope
- reason: "Belongs to another part of the 'ESET APT Activity Report Q2 2026\u2013\
Q3 2026' series."
stage: defense-evasion-llm-safety-trigger
status: out_of_scope
guardrails:
claims: no_unsupported
evidence: citation_required
missing_data: not_benign
telemetry: untrusted
hunt:
applicability: campaign-specific
handoff: promote-to-detection
justification: Compromise of the software supply chain through developer credential
theft allows for stealthy, persistent access that can affect every downstream
user; identifying these injections before they reach production is a critical
security obligation.
methodology: model-assisted
trigger: intel-report
hypothesis: An adversary has compromised developer credentials to harvest sensitive
repository secrets and inject malicious code into private source code repositories,
bypassing standard CI/CD protections.
labels:
- hunt
- attack.t1555
- attack.t1195
- attack.t1078
- credential access
- defense evasion
- execution
- initial access
name: Development Pipeline Credential Abuse and Injection
parameters:
lookback_days:
default: '14'
description: Days of history to examine.
from:
kind: manual
observed: '2026-10-28'
ref: hunt-standard
type: number
scope_actors:
default: []
description: Developer accounts identified in the lead query to pivot on.
from:
kind: manual
observed: '2026-10-28'
ref: lead-pivot
type: list[string]
target_repos:
default: []
description: Critical repositories to focus on; empty means all.
from:
kind: manual
observed: '2026-10-28'
ref: inventory
type: list[string]
provenance:
authors:
- name: Huntbase hunt generation
org: huntbase.io
generated:
by: huntbase-hunt-generation
from: https://www.welivesecurity.com/en/eset-research/eset-apt-activity-report-q2-2026-q3-2026/
gates:
- dry-run
- lint
model: hb_google/gemini-3-flash-preview
rationale: Focus the hunt on critical repositories that control deployment pipelines
and prioritize accounts with maintainer access.
references:
- name: "ESET APT Activity Report Q2 2026\u2013Q3 2026"
url: https://www.welivesecurity.com/en/eset-research/eset-apt-activity-report-q2-2026-q3-2026/
related:
- hunt: initial-access-mdaemon-exploit
reason: Mail server exploitation is a separate initial access vector mentioned in
the same report.
relation: out-of-scope-alternative
scenario:
stages:
- name: MDaemon Mail Server Exploitation
observables:
- MDaemon mail servers
- HELLAGE backdoor
- HELLTAG backdoor
slug: initial-access-mdaemon-exploit
tactic: initial-access
techniques:
- T1190
- name: Recruitment-Themed Phishing
observables:
- recruitment-themed social engineering
- AI-generated phishing lure images
slug: initial-access-recruitment-phishing
tactic: initial-access
techniques:
- T1566
- name: Developer Credential Harvesting
observables:
- harvesting developer credentials
- private source code repositories
slug: credential-access-developer-harvesting
tactic: credential-access
techniques:
- T1555
- name: Source Code Injection
observables:
- injecting malicious code into public and private source code repositories
slug: initial-access-supply-chain-injection
tactic: initial-access
techniques:
- T1195
- name: Backdoor Execution
observables:
- PteroBox
- PteroPSDoor
- Rezzuar
- HELLAGE
- HELLTAG
slug: execution-backdoor-deployment
tactic: execution
techniques:
- T1059
- name: AI Guardrail Evasion Decoy
observables:
- decoy request for instructions on building a nuclear weapon into a script comment
slug: defense-evasion-llm-safety-trigger
tactic: defense-evasion
techniques:
- T1027
summary: APT groups in Q2-Q3 2026 targeted development environments via credential
harvesting and source code injection, exploited MDaemon mail servers to deploy
backdoors, and utilized AI-generated content and decoys for social engineering
and defense evasion. Notable activities include North Korean DeceptiveDevelopment's
supply chain attacks and the first documented destructive operation by Belarus-aligned
FrostyNeighbor.
series:
index: 1
slug: eset-apt-activity-report-q2-2026-q3-2026
title: "ESET APT Activity Report Q2 2026\u2013Q3 2026"
total: 2
severity: critical
targets:
analyst:
name: Tier-2 analyst
role: analyst
endpoint:
category: endpoint
name: Endpoint telemetry (hb_ surfaces)
telemetry:
- endpoint
hunter:
agent: true
name: Hunt agent
identity:
category: identity
name: Identity / sign-in telemetry
telemetry:
- identity
tlp: clear
type: investigation
---
# Development Pipeline Credential Abuse and Injection
This hunt targets the code-injection tradecraft observed in North Korea-aligned campaigns where compromised developer credentials grant access to repositories and secrets. The hunt identifies unauthorized repository modifications in the GitHub audit log and correlates them with anomalous sign-in patterns and secret enumeration. The flow isolates the supply chain risk at the point of injection and pivots to identity telemetry to confirm the compromise.
## github-push-events
<!-- Detect unauthorized pushes and repository updates -->
Detect unauthorized pushes or commits to source code repositories.
```sqlite target=endpoint role=detection-candidate params=(lookback_days=lookback_days, target_repos=target_repos)
~~~yaml
expected: Push events from developer accounts, particularly those associated with
critical production repositories. Silence suggests no modifications were logged
via the GitHub API.
reads:
- actor_user_name
- resource_name
- src_endpoint_ip
- api_operation
- user_agent
- time
silence: not_evidence_of_absence
source: hb_cloud_api_activity
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT actor_user_name, resource_name, src_endpoint_ip, api_operation, user_agent, time FROM hb_cloud_api_activity WHERE provider = 'github' AND activity_id = 3 AND (LOWER(api_operation) LIKE '%push%' OR LOWER(api_operation) LIKE '%update%' OR LOWER(api_operation) LIKE '%commit%') AND ('{{target_repos}}' = '' OR instr(',' || '{{target_repos}}' || ',', ',' || resource_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## corroborate-behavior
<!-- Corroborate pushes with identity and secret access -->
parallel:
- → secret-access-prevalence
- → high-risk-authentication
join: → triage-session-compromise
## secret-access-prevalence
<!-- Prevalence of secret enumeration -->
Identify if the actors were reading repository secrets, highlighting users who perform these operations rarely.
```sqlite target=endpoint role=baseline params=(lookback_days=lookback_days, scope_actors=scope_actors)
~~~yaml
baseline:
compare: first_seen
window: '{{lookback_days}}d'
expected: Developers reading repository secrets outside of standard automated patterns.
Silence suggests no rare secret harvesting was detected.
prevalence:
by: actor_user_name
key:
- api_operation
rare_below: 3
reads:
- api_operation
- actor_user_name
- time
silence: not_evidence_of_absence
source: hb_cloud_api_activity
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT LOWER(api_operation) AS operation, COUNT(DISTINCT actor_user_name) AS users, COUNT(*) AS calls, MIN(time) AS first_seen FROM hb_cloud_api_activity WHERE provider = 'github' AND activity_id = 2 AND (LOWER(api_operation) LIKE '%secret%' OR LOWER(api_operation) LIKE '%key%' OR LOWER(api_operation) LIKE '%token%') AND ('{{scope_actors}}' = '' OR instr(',' || '{{scope_actors}}' || ',', ',' || actor_user_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days') GROUP BY operation HAVING users <= 3 ORDER BY users ASC
```
## high-risk-authentication
<!-- High-risk authentication context -->
Check for sign-in anomalies such as high risk levels or unusual source IPs for the actors in question.
```sqlite target=identity role=enrichment params=(lookback_days=lookback_days, scope_actors=scope_actors)
~~~yaml
expected: A sign-in with an 'atRisk' state or a failed authentication attempt preceding
the push activity. Silence means no anomalous logins were detected.
reads:
- actor_user_name
- src_endpoint_ip
- src_location_country
- risk_state
- status
- time
silence: not_evidence_of_absence
source: hb_auth_signin
verified: dry-run
verified_at: '2026-10-29'
~~~
SELECT actor_user_name, src_endpoint_ip, src_location_country, risk_state, status, time FROM hb_auth_signin WHERE provider IN ('github', 'azure_ad', 'okta') AND (risk_state != 'none' OR status != 'Success') AND ('{{scope_actors}}' = '' OR instr(',' || '{{scope_actors}}' || ',', ',' || actor_user_name || ',') > 0) AND time >= datetime('now', '-{{lookback_days}} days')
```
## triage-session-compromise
<!-- Triage session compromise -->
```agent target=hunter
cite: required
context:
- github-push-events
- secret-access-prevalence
- high-risk-authentication
max_iterations: 6
objective: Determine if pushes were performed by developer accounts that also show
signs of rare secret harvesting or high-risk authentication. Look for time-boxed
correlation between a risky authentication event and the first secret-access or
push event for each account.
success_criteria: A verdict of malicious or suspicious for any account involved in
push events from anomalous sources or after rare secret access.
tools:
- endpoint
- identity
```
## route-on-verdict
<!-- Route on verdict -->
if~: "the triage verdict is malicious for at least one developer account" (confidence: high, judge=hunter)
then: → revoke-developer-sessions
indeterminate: → manual-commit-review
unavailable: → manual-commit-review (blind_spot: limited-diff-visibility)
else: → close-out
## revoke-developer-sessions
<!-- Revoke developer sessions -->
```action target=identity
~~~yaml
approval: required
~~~
Revoke all active Personal Access Tokens (PATs) and web sessions for the compromised developer account in GitHub.
```
→ manual-commit-review
## manual-commit-review
<!-- Manual commit and diff review -->
```manual target=analyst
Manually inspect the repository diffs for the commits identified in the lead query. Look for unauthorized changes to build scripts or dependencies.
```
→ close-out
## close-out
<!-- Record remediation and findings -->
```manual target=analyst
Document the scope of the exposure and the remediation steps taken. Determine if the lead query warrants a permanent detection rule.
```
→ end
Run it
Take this hunt into your environment.
Open it in Huntbase to run every step against your own connections, with Scout weighing the evidence and your analysts in command. Or take the open hunt.md file anywhere that reads the format.
Machine-drafted by huntbase-hunt-generation using hb_google/gemini-3-flash-preview, gated by dry-run, lint, then reviewed by a person.