Back to skill

Security audit

DHL Tracking

Security checks for vulnerabilities and agentic risk

Overview

This skill is a self-contained DHL tracking helper that stores local shipment state and sends only tracking data to DHL, with one narrow local-file handling bug to be aware of.

Install only if you are comfortable storing DHL tracking numbers, postal codes, recipient/status details, and cached events in local JSON files. Avoid pointing baseDir at a sensitive shared directory, and treat the test command cautiously because it can overwrite a same-named local backup file.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
bin/dhl-track.ps1:569
Finding

Predictable Backup Path Can Overwrite an Unrelated File

Content
View full analysis

Vulnerability Details

File Location: bin/dhl-track.ps1, lines 569–607
Vulnerability Type: Predictable and unsafe temporary backup file handling
Risk Level: Medium

Vulnerable Code

powershell
$backup = $null
$storePath = Get-StorePath
if (Test-Path $storePath) {
    $backup = $storePath + '.bak-test'
    Move-Item $storePath $backup -Force
}
try {
    $fixture = [PSCustomObject]@{
        shipments = @(
            [PSCustomObject]@{
                piececode = '1234567890'
                description = 'Test shipment'
                plz = '12345'
                international = $false
                addedAt = '2026-01-01T00:00:00+00:00'
                lastChecked = '2026-01-01T00:00:00+00:00'
                lastStatus = 'old status'
                lastStatusDate = '2026-01-01T00:00:00+00:00'
                progressCurrent = 1
                progressMax = 5
                recipientName = 'Test Recipient'
                recipientOrt = '12345 Teststadt'
                preferredDay = ''
                deliveryWindowFrom = ''
                deliveryWindowBis = ''
                delivered = $false
                events = @()
            }
        )
    }
    Save-Json $storePath $fixture
    Show-All | Out-Null
    $store = Load-JsonOrNull $storePath
    if ($store.shipments.Count -ne 1) {
        Write-Host 'FAIL: fixture count mismatch'
        return
    }
    if ($store.shipments[0].lastStatus -ne 'old status') {
        Write-Host 'FAIL: fixture lastStatus mismatch'
        return
    }
    Write-Host 'PASS'
} finally {
    if (Test-Path $storePath) {
        Remove-Item $storePath -Force
    }
    if ($backup -and (Test-Path $backup)) {
        Move-Item $backup $storePath -Force
    }
}

Technical Analysis

The test command derives its backup path by appending the fixed suffix .bak-test to the con ...[truncated 1797 chars]

Remediation
View remediation

Remediation Suggestions

  • Generate a unique backup name using a cryptographically random value, such as [System.IO.Path]::GetRandomFileName().
  • Place test fixtures and backups in a dedicated temporary directory rather than beside production state.
  • Do not use -Force when creating the backup; fail safely if the destination unexpectedly exists.
  • Validate that the resolved backup and fixture paths remain within the intended temporary directory.
  • Restrict baseDir to an approved state directory if arbitrary absolute paths are not required.
  • Use atomic replacement or copy-and-restore operations with explicit error checks.
  • Preserve and restore the original file in a way that cannot overwrite unrelated files.
  • Add a regression test covering pre-existing backup-path collisions and interrupted restoration.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (8)

YARA rule 'reverse_shell': Reverse shell patterns in scripts or source code [malware]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · bin/dhl-track.ps1 (reported line 499)May include surrounding context.

text
})
    Save-Json $storePath $store
    Write-Host (L 'remove.done' @($piececode, ($before - $store.shipments.Count)))
}

# ============================================================================
# Doctor / Test (no-op fixtures, sanity)
# ============================================================================

function Test-EndpointReachable($tcpHost, $tcpPort) {
    try {
        $tcp = New-Object System.Net.Sockets.TcpClient
        $iar = $tcp.BeginConnect($tcpHost, $tcpPort, $null, $null)
        $ok = $iar.AsyncWaitHandle.WaitOne(3000, $false)
        if (-not $ok) { $tcp.Close(); return @{ ok = $false; detail = "TCP connect to ${tcpHost}:${tcpPort} timed out" } }
        $tcp.EndConnect($iar)
        $tcp.Close()
        return @{ ok = $true; detail = "TCP connect to ${tcpHost}:${tcpPort} succeeded" }
    } catch {
        return @{ ok = $false; detail = "TCP connect to ${tcpHost}:${tcpPort} failed: $($_.Exception.Message)" }
    }
}

function Invoke-Doctor {
    Write-H

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This manifest-like JSON embeds fixed Accept-Language headers for many countries, such as en-US, de-DE, fr-FR, and others, which can force a specific language/locale behavior without any visible user opt-in in this file. The policy allows locale constraints when user choice is offered or the constraint is clearly documented and justified, but this file provides neither beyond country-based defaults.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The header states the skill does one thing—query DHL—and explicitly says it does not modify anything. However, the script creates and updates local state via Save-Json, including setup.json/store.json writes during setup, add, refresh, remove, and test flows (for example L207-L213, L295, L393, L455, L489, L598). This is an intent/documentation contradiction rather than a mere omission because the comment uses absolute language.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The locale resolution hard-codes de when no user-specified locale is present. This imposes a specific language by default rather than offering a language choice or requiring explicit opt-in, which matches the natural-language locale policy violation criteria.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

In the non-interactive setup path, the script announces and saves locale = de automatically. Because this behavior sets a specific language in persistent configuration without opt-in, it conflicts with the stated language/locale policy requirements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
80% confidence
Finding

The file defines a specific language locale (Deutsch, de) and contains only German user-facing strings. Under the policy rule, locale-specific behavior should either offer user choice or be clearly documented as justified; this file itself contains no such opt-in or justification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

The metadata states these English source strings are translated to German and applied when locale=de, which encodes a specific locale behavior in natural language. This can conflict with the policy requirement to avoid forcing a language unless the locale constraint is explicitly justified or the user is given a choice, and this file does not itself provide such justification beyond the locale tag.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This JSON defines the skill locale as English via natural-language metadata and strings, and the file itself shows no indication of user opt-in or language selection. Because SQP-3 applies to all file types and covers forced language policies, this is a mild policy concern unless language choice is documented elsewhere.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.