Back to skill

Security audit

test

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed embedded-firmware helper with no install scripts, but its own sample code includes unsafe patterns that could be copied into real device firmware.

Review this skill before installing if you expect production-ready firmware templates. It appears low risk to the host environment, but users should not copy its RTOS or SPI examples without adding return-value checks, timeouts, and explicit safe-failure handling.

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 (2)

T09 · Insecure Skill Coding Practices

Warning
Location
AGENTS.md:39
Finding

Unbounded SPI polling can indefinitely halt firmware execution

Content
View full analysis

Vulnerability Details

File Location: AGENTS.md:39-43
Vulnerability Type: Unbounded busy-wait and misleading non-blocking implementation
Risk Level: Medium

Vulnerable Code

c
void spi_write_byte(SPI_TypeDef *spi, uint8_t data) {
    while (!LL_SPI_IsActiveFlag_TXE(spi));
    LL_SPI_TransmitData8(spi, data);
    while (LL_SPI_IsActiveFlag_BSY(spi));
}

Technical Analysis

The function polls the SPI TXE and BSY flags without a timeout, cancellation mechanism, watchdog interaction, or error return. Although the surrounding heading describes the transfer as non-blocking, both while statements are synchronous and can wait forever.

The SPI flags may remain in an unexpected state because of peripheral misconfiguration, clock failure, hardware faults, bus contention, or deliberate manipulation of an attached device. If that occurs, control never returns to the caller. This contradicts the skill's explicit requirement in AGENTS.md:8 and SKILL.md:24 that peripheral drivers must never block indefinitely.

Because this is presented as an authoritative implementation template, generated firmware may reproduce the unsafe pattern.

Attack Path

  1. Firmware generated from the skill incorporates the provided SPI transfer pattern.
  2. An attacker with access to the device or SPI bus induces a peripheral fault, clock disruption, or bus condition that prevents TXE from becoming active or BSY from clearing.
  3. The processor remains inside one of the unbounded polling loops.
  4. The affected task or entire bare-metal execution path stops making progress.
  5. The device becomes unavailable until a watchdog or external reset occurs. Repeatedly inducing the condition may create a persistent denial of service.

Impact Assessment

This issue does not grant additional software privileges or direct access to confidential information. Its primary impact is availability loss within firmware that ...[truncated 320 chars]

Remediation
View remediation

Remediation Suggestions

  • Replace unbounded flag polling with deadline-based waits.
  • Return a status value such as bool, an STM32 error code, or a project-specific result enum.
  • Reset or safely reinitialize the SPI peripheral after a timeout where supported.
  • Propagate transfer failures to the caller and place outputs in a defined safe state.
  • Use interrupt- or DMA-driven transfers if the example is intended to be genuinely non-blocking.
  • Add tests that hold TXE inactive and BSY active to verify bounded recovery.

Example hardened interface:

c
spi_status_t spi_write_byte(SPI_TypeDef *spi,
                            uint8_t data,
                            uint32_t deadline_ticks) {
    while (!LL_SPI_IsActiveFlag_TXE(spi)) {
        if (deadline_expired(deadline_ticks)) {
            return SPI_STATUS_TIMEOUT;
        }
    }

    LL_SPI_TransmitData8(spi, data);

    while (LL_SPI_IsActiveFlag_BSY(spi)) {
        if (deadline_expired(deadline_ticks)) {
            return SPI_STATUS_TIMEOUT;
        }
    }

    return SPI_STATUS_OK;
}

T09 · Insecure Skill Coding Practices

Warning
Location
AGENTS.md:29
Finding

FreeRTOS initialization failures are ignored before resources are used

Content
View full analysis

Vulnerability Details

File Location: AGENTS.md:29-32
Vulnerability Type: Unchecked resource allocation and task-creation results
Risk Level: Medium

Vulnerable Code

c
void app_main(void) {
    sensor_queue = xQueueCreate(8, sizeof(sensor_data_t));
    xTaskCreate(sensor_task, "sensor", TASK_STACK_SIZE, NULL, TASK_PRIORITY, NULL);
}

The resulting task later uses the queue without validating its handle:

c
static void sensor_task(void *arg) {
    sensor_data_t data;
    while (1) {
        if (read_sensor(&data) == ESP_OK) {
            xQueueSend(sensor_queue, &data, pdMS_TO_TICKS(10));
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

Technical Analysis

xQueueCreate can return NULL when allocation fails. xTaskCreate returns a status indicating whether the task was created. The template ignores both results and provides no cleanup or safe failure path.

Under constrained or fragmented memory conditions, queue creation may fail while task creation succeeds. The task then passes an invalid queue handle to xQueueSend. Depending on the FreeRTOS configuration, assertions, and port behavior, this can trigger a panic, watchdog reset, or undefined system behavior. Conversely, task creation can fail silently, leaving the sensing function unavailable while the rest of the firmware appears to have initialized normally.

This pattern conflicts with the return-value checking rule in SOUL.md:11 and with the project's stated requirement to handle error paths.

Attack Path

  1. Firmware generated from the skill uses the provided initialization template.
  2. Available heap is reduced through normal memory pressure, fragmentation, oversized configuration, or attacker-triggerable resource consumption elsewhere in the device.
  3. xQueueCreate or xTaskCreate fails.
  4. The failure is ignored, so initialization continues without the required queue or task. 5 ...[truncated 786 chars]
Remediation
View remediation

Remediation Suggestions

  • Check the queue handle against NULL immediately after creation.
  • Check that xTaskCreate returns pdPASS.
  • Delete the queue if subsequent task creation fails.
  • Log the exact failure and enter an explicit safe state rather than continuing with partial initialization.
  • Prefer xQueueCreateStatic and xTaskCreateStatic where the skill's prohibition on post-initialization dynamic allocation and deterministic memory requirements apply.
  • Add fault-injection tests that force queue and task allocation failures.

Example hardened initialization:

c
void app_main(void) {
    sensor_queue = xQueueCreate(8, sizeof(sensor_data_t));
    if (sensor_queue == NULL) {
        ESP_LOGE(TAG, "Failed to create sensor queue");
        enter_safe_state();
        return;
    }

    BaseType_t result = xTaskCreate(
        sensor_task,
        "sensor",
        TASK_STACK_SIZE,
        NULL,
        TASK_PRIORITY,
        NULL
    );

    if (result != pdPASS) {
        ESP_LOGE(TAG, "Failed to create sensor task");
        vQueueDelete(sensor_queue);
        sensor_queue = NULL;
        enter_safe_state();
    }
}
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (2)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This is a true issue: the example is explicitly labeled 'non-blocking' but uses polling loops that wait indefinitely on TXE and BSY flags. In embedded firmware, such unbounded busy-waits can deadlock a task, starve lower-priority work, trigger watchdog resets, and mislead downstream users into adopting unsafe driver patterns under the false assumption that they are non-blocking.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The phrase "Reference this agent by name or specialty when you need its expertise" does not define specific trigger phrases or clear activation boundaries. In particular, invoking by "specialty" is ambiguous and could overlap with many general requests about firmware or embedded systems, increasing the chance of unintended activation.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.