# Detections

{% hint style="warning" %}
Available for **Enterprise** Tier only
{% endhint %}

Harden-Runner can monitor outbound runtime detections to help you stay informed about security risks in your GitHub Actions workflows. You can review all past runtime detections on the **Detections** page under the **Harden-Runner** menu.

{% hint style="info" %}
Harden-Runner detects compromised npm packages at runtime. For PR-level prevention, see [NPM Supply Chain Security → Prevent](/npm-supply-chain-security/prevent.md)
{% endhint %}

## Types of Detections

The **Detections** page covers **ten** critical areas:

1. Secrets in Build Logs
2. Secrets in Artifacts
3. Outbound Calls Blocked
4. Anomalous Outbound Network Calls
5. Suspicious Outbound Network Calls
6. Source Code Overwritten
7. HTTPS Outbound Network Calls
8. Action Uses Imposter Commit
9. Suspicious Process Events
10. Agent Tampered

Each detection is linked to the relevant GitHub Actions workflow and run and includes direct links to the run and the insights URL that indicates where the detection happened.&#x20;

### **Secrets in Build Logs**

**When it triggers:** A line in the workflow's build log contains a value matching a known secret pattern (API keys, cloud credentials, OAuth tokens, and similar). Each detection includes a masked preview and a link to the offending log line.

**Why it matters:** Build logs are visible to anyone with read access to the workflow run, which on public repos includes external contributors. Anything written to a log is effectively permanent because logs and forks may be archived long after the secret is rotated. Tools like the Azure, AWS, and Google Cloud CLIs occasionally print credentials by accident, and catching these at runtime lets you rotate the value before it is harvested.

<figure><img src="/files/NOYV5N6lQvIuvey695BZ" alt=""><figcaption></figcaption></figure>

### **Secrets in Artifacts**

**When it triggers:** An artifact uploaded by the workflow (via `actions/upload-artifact` or similar) contains an embedded value matching a known secret pattern.

**Why it matters:** Artifacts are downloadable by anyone with access to the workflow run and are often retained for weeks. A `.env` file, config bundle, or compiled binary that accidentally embeds a credential becomes a long-lived public exposure. Detecting it at publish time lets you delete the artifact and rotate the secret before it is downloaded.

<figure><img src="/files/cKACxHzI6peQzxxdBg8D" alt=""><figcaption></figcaption></figure>

### **Outbound Calls Blocked**

**When it triggers:** A workflow running with `egress-policy: block` attempts to reach a destination that is not on its allowlist, and Harden-Runner blocks the call.

**Why it matters:** Egress blocks are the enforcement layer that stops exfiltration in real time, but reviewing them is what closes the loop. A legitimate block means the allowlist needs updating; a malicious block means the runner was actively compromised and the secrets it had access to should be rotated. Calls blocked specifically because they hit a [Global Block List](/harden-runner.md#global-block-list) IOC are labeled **Attack Blocked** so you can tell them apart from routine policy blocks.

<figure><img src="/files/VSrvm5Ul7OzVEsJ8n0Qi" alt=""><figcaption></figcaption></figure>

### **Anomalous Outbound Network Calls**

**When it triggers:** A workflow contacts a destination that is new or unusual relative to the baseline Harden-Runner has built for that workflow's outbound traffic. The baseline must be stable; runs against an unstable or still-forming baseline do not generate this alert.

**Why it matters:** Most CI/CD supply chain attacks rely on exfiltrating data to a previously-unseen attacker domain. Baseline comparison catches that first-time call even when the workflow is running in `audit` mode. This is the detection that surfaced the [tj-actions/changed-files compromise](https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised) (CVE-2025-30066).

<figure><img src="/files/xoeHiv15H5P1svAr3ZoK" alt=""><figcaption></figcaption></figure>

### **Suspicious Outbound Network Calls**

**When it triggers:** A workflow contacts a domain or IP that StepSecurity's 24×7 SOC has identified as an indicator of compromise (IOC) and added to the [Global Block List](https://docs.stepsecurity.io/github/harden-runner#global-block-list). The call is blocked automatically, even in `audit` mode.

**Why it matters:** Anomalous-call detection needs a baseline; suspicious-call detection does not. As soon as StepSecurity confirms an IOC during an active investigation, every protected workflow gains protection without a config change or an action version bump. The [pgserve npm compromise](https://www.stepsecurity.io/blog/pgserve-compromised-on-npm-malicious-versions-harvest-credentials) was blocked this way in real time. Allowlisting an IOC in your own policy does not override the Global Block List, so a compromised action cannot grant itself access to known-malicious infrastructure.

<figure><img src="/files/UZcbRU5Rnxllmz3sOzh4" alt=""><figcaption></figcaption></figure>

### **HTTPS Outbound Network Calls**

**When it triggers:** Every HTTPS request a workflow makes is logged with its HTTP method, host, and path. Unlike the other detections on this page, this surface is populated continuously rather than triggered by an anomaly.

**Why it matters:** Network-layer logs only show that the runner contacted `api.github.com`. HTTPS-level visibility shows *what* it did there: which APIs were called, which repos were touched, which content was uploaded. That is what surfaces abuse of `GITHUB_TOKEN` itself, for example a compromised action creating issues, pushing branches, or copying repository content to an attacker-controlled fork. It is also the data Harden-Runner uses to recommend minimum `GITHUB_TOKEN` permissions for each job.

<figure><img src="/files/jh9eiMDLvPnbiG2Ty9eN" alt=""><figcaption></figcaption></figure>

### **Source Code Overwritten**

**When it triggers:** A file inside the checked-out source tree is modified during the build. Harden-Runner records the modifying executable and the syscall details, using the Linux Audit Framework on Ubuntu runners.

**Why it matters:** Source-code tampering during the build is the SolarWinds and XZ Utils attack class: a backdoor is injected at compile time so the source on disk and the binary that ships no longer match. Branch protection, code review, and code signing all run before or after the build, so none of them can catch this. File-write monitoring is what closes that gap. Infrastructure-as-code files (Terraform, Kubernetes manifests, and so on) are monitored alongside application source for the same reason.

<figure><img src="/files/c3nikDorPCfqX4RQm6Eu" alt=""><figcaption></figcaption></figure>

### **Action Uses Imposter Commit**

**When it triggers:** A workflow references a GitHub Action by a tag or commit SHA that does not exist on the action repository's default branch. The pinned commit lives outside the action's normal release history, often in a fork.

**Why it matters:** Updating a tag to point at a commit outside the default branch is a known supply-chain attack pattern, used in the tj-actions and reviewdog incidents. Because the malicious commit never lands on the default branch, it bypasses PR review entirely, which is what makes the attack easy to miss. Some legitimate actions also trigger this signal: projects that build release artifacts on a short-lived branch and then delete it after tagging produce the same warning sign without anything malicious happening. Triage each detection before treating it as an attack.

<figure><img src="/files/cn8kdJrH5z8YzmLNpFB8" alt=""><figcaption></figcaption></figure>

### **Suspicious Process Events**

Harden-Runner monitors process activity on the runner and flags behaviors that match known supply-chain attack techniques. Three subtypes are surfaced today: **Privileged Container**, **Reverse Shell**, and **Runner.Worker Memory Read**. Each is a high-confidence signal, and each can be configured to terminate the affected job automatically via [Lockdown Mode](/harden-runner/policy-store.md#lockdown-mode).

#### **Privileged Container**

**When it triggers:** A workflow launches a privileged container, for example via `docker run --privileged`, by mounting the host filesystem into a container, or by starting a container directly through the Docker or containerd socket.

**Why it matters:** Privileged containers can break out of container isolation and gain root on the runner host.&#x20;

#### **Reverse Shell**

**When it triggers:** A process spawned during the workflow opens an outbound connection to a remote host and proxies an interactive shell over it. Common patterns include `bash -i` redirected to `/dev/tcp`, `nc -e`, and Python or Perl one-liners that wire `socket` calls to `subprocess`.

**Why it matters:** A reverse shell gives an attacker live, interactive control of the runner. From that position they can read the workflow's environment (including `GITHUB_TOKEN` and injected secrets), exfiltrate source code and build artifacts, and pivot to other systems reachable from the runner.

#### **Runner.Worker Memory Read**

**When it triggers:** Another process on the runner reads the memory of the GitHub Actions `Runner.Worker` process, typically via `/proc/<pid>/mem` or `ptrace` on Linux, or `ReadProcessMemory` on Windows.

**Why it matters:** GitHub Actions secrets are decrypted into the `Runner.Worker` process at job runtime. Anything that can read that memory can extract those secrets in plaintext, regardless of how they are masked in logs. This is the technique used in the [tj-actions/changed-files compromise](https://www.stepsecurity.io/blog/harden-runner-detection-tj-actions-changed-files-action-is-compromised) (CVE-2025-30066). Legitimate workflows have no reason to read this memory, so the signal has a very low false-positive rate.

<figure><img src="/files/BRkfQj0f2R8kqXRFgv6J" alt=""><figcaption></figcaption></figure>

### **Agent Tampered**

Detects when the Harden-Runner agent has been tampered with during workflow execution.

<figure><img src="/files/PqNJNLhGcgNzURrVJCT4" alt=""><figcaption></figcaption></figure>

## **How to Suppress a Detection**

Suppressing a detection hides it from your active list without marking it as fixed. Use suppression when the detection is a false positive, not relevant, or represents an acceptable risk. Suppressed detections remain available under the “Suppressed” tab for future review, and can be unsuppressed if needed

**Step 1:** Click the three dots next to the item you want to suppress, then select “Suppress Detection.”

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/32f8a06f-4c9e-42b3-ba5b-0682c6f3cd92/ascreenshot.jpeg?tl_px=272,36\&br_px=3024,1575\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=990,277)

**Step 2:** Select a reason for suppressing the detection.

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/466fe23f-a442-4a61-ab86-f024c8f7a04f/ascreenshot.jpeg?tl_px=0,0\&br_px=2752,1538\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=411,223)

**Step 3:** Click "Suppress"

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/1ff4f313-6454-46d0-aafb-fbba803fb65b/ascreenshot.jpeg?tl_px=272,183\&br_px=3024,1722\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=647,416)

**Step 4:** Go to the “Suppressed” tab to view all suppressed detections

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/171443e1-a78e-4aab-8876-627e98c40fc0/ascreenshot.jpeg?tl_px=272,158\&br_px=3024,1697\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=563,276)

## **How to Resolve a Detection**

Resolving a detection indicates that you have addressed the underlying issue. Use this option after taking corrective action, such as updating a workflow, fixing a configuration, or applying a patch. Resolved detections move out of the active list but remain in the system for audit and traceability.

**Step 1:** Click the three dots next to the item you want to resolve, then select “Resolve Detection.”

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/485b22e7-d530-457d-9e16-5231ddbae91b/ascreenshot.jpeg?tl_px=272,0\&br_px=3024,1538\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=1026,262)

**Step 2:** Give a reason for resolving the detection.

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/afa345e8-7d78-4296-8952-216b8b483bee/ascreenshot.jpeg?tl_px=0,31\&br_px=3024,1721\&force_format=jpeg\&q=100\&width=1120.0)

**Step 3:** Click "Resolve"

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/5bcedbc0-fbfd-4c90-8eeb-b5587a33b466/ascreenshot.jpeg?tl_px=272,183\&br_px=3024,1722\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=661,327)

**Step 4:** Go to the “Resolved” tab to view all resolved detections

![](https://ajeuwbhvhr.cloudimg.io/https://colony-recorder.s3.amazonaws.com/files/2025-09-28/38711e43-a49f-407d-a292-5f4e6ddebb15/ascreenshot.jpeg?tl_px=272,180\&br_px=3024,1719\&force_format=jpeg\&q=100\&width=1120.0\&wat=1\&wat_opacity=1\&wat_gravity=northwest\&wat_url=https://colony-recorder.s3.amazonaws.com/images/watermarks/8B5CF6_standard.png\&wat_pad=825,276)

## **Real-Time Security Alerts**

StepSecurity delivers real-time alerts for runtime detections, ensuring you stay informed about potential security threats as they happen.

To minimize alert fatigue, notifications are sent only once per event, covering all repositories in your GitHub organization. This approach maintains visibility into security events without overwhelming your team.

Follow the instructions in [Notification Settings](/settings/notifications.md) to configure your alerts.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.stepsecurity.io/harden-runner/detections.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
