Back to skill

Security audit

Oban Designer

Security checks for vulnerabilities and agentic risk

Overview

This skill is a documentation-only Oban helper, but some examples promote unsafe webhook and CSV-import worker patterns that could expose data or overwrite records if copied into an application.

Review this skill before installing or using its examples directly. It is not malware and has no executable installer, but users should add their own security controls before generating webhook or import workers: validate webhook destinations, avoid secrets in job args, use trusted upload IDs instead of raw paths, enforce tenant authorization, limit import size, and make overwrite behavior explicit.

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

T09 · Insecure Skill Coding Practices

Error
Location
references/worker-patterns.md:58
Finding

Unrestricted Webhook Destination Enables Server-Side Request Forgery

Content
View full analysis

Vulnerability Details

File Location: references/worker-patterns.md:58-63
Vulnerability Type: Server-Side Request Forgery (SSRF)
Risk Level: High

elixir
@impl Oban.Worker
def perform(%Oban.Job{args: args, attempt: attempt}) do
  %{"url" => url, "event" => event, "payload" => payload} = args
  headers = build_headers(args)

  case Req.post(url, json: payload, headers: headers, receive_timeout: 25_000) do

Technical Analysis

The worker obtains the destination URL directly from attacker-influenceable Oban job arguments and passes it to Req.post/2 without validating the scheme, hostname, port, resolved IP address, or redirect destination.

If an untrusted user can enqueue a job or influence its arguments, the application server can be induced to issue requests to destinations unavailable to the attacker directly. Relevant targets include:

  • Loopback services such as 127.0.0.1 or ::1
  • Private network addresses
  • Link-local addresses and cloud instance metadata endpoints
  • Internal administrative APIs
  • Services exposed through DNS rebinding or redirects

A request timeout limits request duration but does not prevent SSRF.

Attack Path

  1. An attacker gains the ability to create or influence a webhook delivery job.
  2. The attacker places an internal or otherwise restricted destination in the job's "url" argument.
  3. Oban executes the worker in the trusted application environment.
  4. Req.post/2 sends the supplied payload to the attacker-selected destination.
  5. The attacker uses response-dependent behavior, logs, or observable side effects to probe or interact with the target.
  6. If the target is a metadata service or privileged internal API, the request may expose credentials or perform sensitive operations.

Impact Assessment

Exploitation provides access to network resources reachable by the application worker. Depending on network placement and target behavior, ...[truncated 336 chars]

Remediation
View remediation

Remediation Suggestions

  • Store only a trusted webhook or subscriber identifier in job arguments.
  • Resolve the destination URL from an application-controlled database record at execution time.
  • Require an approved scheme such as HTTPS.
  • Allowlist expected hostnames and ports where practical.
  • Resolve hostnames and reject loopback, private, link-local, multicast, and reserved addresses for both IPv4 and IPv6.
  • Revalidate the resolved address immediately before connecting to reduce DNS-rebinding risk.
  • Disable redirects or validate every redirect destination using the same policy.
  • Apply outbound firewall or proxy controls that deny access to internal and metadata networks.
  • Restrict which application roles may create webhook subscriptions or enqueue webhook jobs.
  • Add tests covering encoded IP addresses, IPv6, redirects, DNS rebinding, and cloud metadata endpoints.

T09 · Insecure Skill Coding Practices

Warning
Location
references/worker-patterns.md:58
Finding

Webhook Signing Secret Is Persisted in Oban Job Arguments

Content
View full analysis

Vulnerability Details

File Location: references/worker-patterns.md:58-82
Vulnerability Type: Plaintext Sensitive Data Storage
Risk Level: Medium

elixir
@impl Oban.Worker
def perform(%Oban.Job{args: args, attempt: attempt}) do
  %{"url" => url, "event" => event, "payload" => payload} = args
  headers = build_headers(args)

  case Req.post(url, json: payload, headers: headers, receive_timeout: 25_000) do
    {:ok, %{status: status}} when status in 200..299 ->
      :ok

    {:ok, %{status: 410}} ->
      Logger.info("Webhook endpoint gone: #{url}")
      {:cancel, "endpoint returned 410 Gone"}

    {:ok, %{status: status, body: body}} ->
      Logger.warning("Webhook failed: #{status} - #{inspect(body)}")
      {:error, "HTTP #{status}"}

    {:error, %Req.TransportError{reason: reason}} ->
      {:error, "transport: #{inspect(reason)}"}
  end
end

defp build_headers(%{"secret" => secret} = args) do
  payload = Jason.encode!(args["payload"])
  signature = :crypto.mac(:hmac, :sha256, secret, payload) |> Base.encode16(case: :lower)
  [{"x-webhook-signature", signature}, {"content-type", "application/json"}]
end

Technical Analysis

The worker expects the webhook signing secret to be present in the "secret" field of its job arguments. Oban persists job arguments in its database, so the secret may remain available beyond the immediate execution of the worker.

This expands secret exposure to systems and identities that can access job records, including database operators, administrative dashboards, backups, replicas, debugging tools, telemetry pipelines, and support tooling. Retried, scheduled, retained, or failed jobs may extend the exposure period.

Attack Path

  1. A webhook job is created with its signing secret in the job argument map.
  2. Oban serializes and persists the argument map in the jobs database.
  3. A user or compromised component with access to job reco ...[truncated 756 chars]
Remediation
View remediation

Remediation Suggestions

  • Never include webhook signing secrets in Oban job arguments.
  • Put only a webhook or subscriber identifier in the job.
  • Retrieve the secret at execution time from a dedicated secret manager or an encrypted application field.
  • Restrict secret retrieval to the worker identity and the specific tenant or subscriber being processed.
  • Encrypt sensitive database fields with separately managed keys.
  • Configure short retention for completed and discarded jobs where operationally appropriate.
  • Review dashboards, telemetry, logs, backups, and replicas for historical exposure.
  • Rotate any signing secret that has already been persisted in job arguments.
  • Ensure error reporting and argument inspection redact fields classified as sensitive.

T09 · Insecure Skill Coding Practices

Warning
Location
references/worker-patterns.md:168
Finding

Job-Controlled Import Path Permits Arbitrary File Access

Content
View full analysis

Vulnerability Details

File Location: references/worker-patterns.md:168-179
Vulnerability Type: Path Traversal and Arbitrary File Read
Risk Level: Medium

elixir
@impl Oban.Worker
def perform(%Oban.Job{args: %{"file_path" => path, "tenant_id" => tenant_id}}) do
  path
  |> File.stream!()
  |> CSV.decode!(headers: true)
  |> Stream.chunk_every(500)
  |> Enum.each(fn batch ->
    entries = Enum.map(batch, &build_entry(&1, tenant_id))
    MyApp.Repo.insert_all(MyApp.Items.Item, entries,
      on_conflict: :replace_all,
      conflict_target: [:tenant_id, :external_id]
    )
  end)

Technical Analysis

The import worker accepts a filesystem path and tenant identifier directly from job arguments. It opens the supplied path with File.stream!/1 without canonicalization, ownership verification, directory confinement, symlink checks, file-type checks, or size limits.

An attacker who can influence job arguments can therefore direct the worker to any file readable by the application account. CSV-compatible contents can be parsed and persisted into application records. Non-CSV files, special files, or extremely large inputs may also trigger errors, excessive processing, or resource exhaustion.

Trusting the supplied tenant_id independently introduces a risk of importing attacker-selected data into another tenant unless authorization is enforced before the job is inserted.

Attack Path

  1. An attacker obtains the ability to enqueue or influence an import job.
  2. The attacker supplies an absolute path, traversal path, or symlink targeting a file readable by the application.
  3. The attacker optionally supplies a victim tenant identifier.
  4. The Oban worker opens the selected file under the application service account.
  5. CSV-compatible content is decoded and written into application records.
  6. The attacker retrieves imported values through normal application interfaces, causes cross- ...[truncated 586 chars]
Remediation
View remediation

Remediation Suggestions

  • Pass an immutable upload identifier rather than a filesystem path in job arguments.
  • Resolve the upload server-side from an application-controlled record.
  • Verify that the requesting principal and job tenant own or are authorized to process the upload.
  • Store imports in a dedicated, non-sensitive directory or isolated object-storage bucket.
  • Canonicalize local paths and verify that the resolved path remains inside the approved import root.
  • Reject symlinks, device files, named pipes, sockets, directories, and other non-regular files.
  • Enforce maximum file size, row count, field length, processing time, and memory limits.
  • Derive the tenant identifier from the trusted upload record instead of accepting it independently.
  • Run import workers with a restricted service account and filesystem permissions.
  • Avoid exposing raw file contents or parser errors through logs and user-visible error messages.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (3)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

This markdown file contains example code for delivering webhook payloads to subscriber endpoints, which is a network operation that transmits user or system data. The section describes the behavior functionally, but it does not include any warning or disclosure about sending payload data to external URLs.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The markdown describes a CSV import worker as importing records, but the example uses on_conflict: :replace_all, which can overwrite existing data. Because this behavior can materially affect user data and is not clearly warned about in the surrounding description, it should be disclosed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

This markdown file includes a webhooks queue and later a WebhookDelivery worker example, which implies outbound network transmission to third-party endpoints. The skill description and examples do not include any user-facing warning about privacy, data handling, or the risks of sending payloads to external services.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.