Back to skill

Security audit

orca-lp

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly transparent about managing Orca liquidity, but its main transaction template can broadcast wallet-signed financial transactions without enforcing the promised confirmation flag.

Review before installing or using for writes. Use a small dedicated wallet only, do not set KEYPAIR_PATH for analytics, pin and install dependencies locally from a lockfile, and add an explicit confirmation check at the transaction-send boundary before running any generated write script.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:692
Finding

Shared Transaction Wrapper Does Not Enforce the Required Confirmation Gate

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:659, SKILL.md:692-718; affected write examples include SKILL.md:242-243, 263, 273, 321-322, 389, 401-402, 432, 466, 482, 486, and 505-527
Vulnerability Type: Missing authorization check before blockchain transaction broadcast
Risk Level: High

Vulnerable Code

The setup declares a confirmation flag:

typescript
const CONFIRM = process.argv.includes("--confirm"); // require --confirm to broadcast

However, the shared transaction wrapper does not inspect that flag:

typescript
async function sendWithRetry(
  txBuilder: TransactionBuilder,
  conn: Connection,
  computeUnits = 400_000,
): Promise<string> {
  const microLamports = await recommendedPriorityFee(conn);
  txBuilder.prependInstruction({
    instructions: [
      ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnits }),
      ComputeBudgetProgram.setComputeUnitPrice({ microLamports }),
    ],
    cleanupInstructions: [],
    signers: [],
  });

  for (let attempt = 1; attempt <= 3; attempt++) {
    let sig: string;
    try {
      sig = await txBuilder.buildAndExecute();
    } catch (e: any) {
      if (attempt < 3 && /Blockhash|expired|BlockheightExceeded/i.test(e.message)) continue;
      throw e;
    }
    for (let i = 0; i < 30; i++) {
      const status = (await conn.getSignatureStatus(sig)).value;
      if (status?.err) throw new Error(`Tx ${sig} failed: ${JSON.stringify(status.err)}`);
      if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") return sig;
      await new Promise(r => setTimeout(r, 1000));
    }
    throw new Error(`Tx ${sig} did not confirm within 30s`);
  }
  throw new Error("unreachable");
}

Write playbooks call the wrapper directly, for example:

typescript
const tx = await pool.swap(quote);
const sig = aw
...[truncated 2023 chars]
Remediation
View remediation

Remediation Suggestions

Enforce confirmation at the single transaction-broadcast boundary rather than relying on every caller:

typescript
async function sendWithRetry(
  txBuilder: TransactionBuilder,
  conn: Connection,
  confirm: boolean,
  computeUnits = 400_000,
): Promise<string> {
  if (!confirm) {
    throw new Error("Dry run only. Pass --confirm to broadcast.");
  }

  // Existing send logic follows.
}

Every call should pass CONFIRM explicitly:

typescript
const sig = await sendWithRetry(tx, connection, CONFIRM);

Additional hardening should include:

  1. Separate preview and execution commands so dry-run code cannot reach a send API.
  2. Simulate transactions before approval and print pool, mint, position, expected amounts, minimum outputs, fees, and slippage bounds.
  3. Require confirmation immediately before signing, after fresh pool data and quotes are obtained.
  4. Add automated tests that mock buildAndExecute() and verify it is never called when confirmation is absent.
  5. Apply the same centralized guard to raw connection.sendTransaction() and sendAndConfirmTransaction() paths.

T09 · Insecure Skill Coding Practices

Error
Location
examples/close-position-anchor.md:138
Finding

Raw Position Close Uses Zero Minimum Token Outputs

Content
View full analysis

Vulnerability Details

File Location: examples/close-position-anchor.md:138-156
Vulnerability Type: Missing withdrawal slippage protection
Risk Level: High

Vulnerable Code

typescript
// V2 decrease liquidity to 0. Same auto-resolution as above.
tx.add(await ctx.program.methods
  .decreaseLiquidityV2(position.liquidity, new BN(0), new BN(0), null)
  .accounts({
    tokenProgramA: tokenProgA,
    tokenProgramB: tokenProgB,
    positionAuthority: owner,
    position: posPda,
    positionTokenAccount,
    tokenMintA: tokenA,
    tokenMintB: tokenB,
    tokenOwnerAccountA: ataA,
    tokenOwnerAccountB: ataB,
    tokenVaultA: vaultA,
    tokenVaultB: vaultB,
    tickArrayLower,
    tickArrayUpper,
  })
  .remainingAccounts([])
  .instruction());

Technical Analysis

The second and third arguments to decreaseLiquidityV2 are the minimum acceptable token A and token B outputs. Both are set to zero while the full position liquidity is withdrawn.

This disables economic slippage protection. Transaction simulation only establishes that the instructions are executable against the simulated state; it does not ensure that the received token amounts remain within limits approved by the user. Pool movement between simulation and inclusion can therefore produce materially different withdrawal amounts without causing the instruction to fail.

The transaction subsequently closes the position and burns its NFT. Consequently, the user cannot reject the result after execution.

Attack Path

  1. A user selects a position and runs the close script.
  2. The script constructs a full-liquidity withdrawal with tokenMinA = 0 and tokenMinB = 0.
  3. Simulation succeeds because the transaction is structurally valid.
  4. The user reruns or continues with --confirm.
  5. Before transaction inclusion, pool price or state changes adversely.
  6. Because both output minima are zero, the on- ...[truncated 905 chars]
Remediation
View remediation

Remediation Suggestions

Replace zero minima with values derived from a fresh liquidity-decrease quote and the user's approved slippage tolerance:

typescript
const quote = decreaseLiquidityQuoteByLiquidityWithParams({
  liquidity: position.liquidity,
  slippageTolerance: Percentage.fromFraction(1, 100),
  sqrtPrice: freshPoolData.sqrtPrice,
  tickCurrentIndex: freshPoolData.tickCurrentIndex,
  tickLowerIndex: position.tickLowerIndex,
  tickUpperIndex: position.tickUpperIndex,
});

tx.add(await ctx.program.methods
  .decreaseLiquidityV2(
    position.liquidity,
    quote.tokenMinA,
    quote.tokenMinB,
    null,
  )
  // accounts...
  .instruction());

The implementation should also:

  1. Refresh pool and position state immediately before producing the quote.
  2. Print estimated and minimum outputs for both tokens before confirmation.
  3. Require the user to approve the exact slippage percentage.
  4. Rebuild and resimulate the transaction if its quote becomes stale.
  5. Abort when either minimum output differs materially from the preview.
  6. Avoid bundling the irreversible position burn unless the bounded withdrawal succeeds atomically.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:631
Finding

Unpinned npx Tooling Can Retrieve and Execute Unreviewed Registry Packages

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:631; invocation examples appear in multiple files under examples/
Vulnerability Type: Unpinned development-tool dependency execution
Risk Level: Medium

Vulnerable Code

text
Sanity-check scripts before sending any tx: `npx tsc --noEmit your-script.ts` catches wrong API signatures and missing exports for free.

Representative example commands include:

bash
npx tsx compare-fee-tiers.ts
npx tsx lp-range-analysis.ts SOL/USDC
npx tsx monitor-pool.ts <pool_address> [interval_sec] [max_polls]
npx tsx pair-discovery.ts
npx tsx pool-detail.ts <pool_address>
npx tsx range-projection.ts SOL/USDC
npx tsx scan-pools.ts
npx tsx stability-rankings.ts

The reviewed project structure contains no package.json or dependency lockfile. Although SKILL.md lists exact versions for the Orca, Solana, Anchor, and utility packages, it does not pin tsx or typescript.

Technical Analysis

When a requested executable is not installed locally, npx can resolve and download a package from the configured package registry. The downloaded package then executes with the invoking user's operating-system privileges.

Because the project does not supply a locked local toolchain, the actual tsx or TypeScript compiler executed by these commands may differ over time from the version reviewed by the Skill author. This weakens the claim that the examples use pinned dependencies and creates a mutable supply-chain execution path.

This is not evidence that the current upstream packages are malicious. The vulnerability is the absence of controls ensuring that only reviewed versions are installed and executed.

Attack Path

  1. A user copies an example into a clean workspace where tsx or tsc is not installed.
  2. The user runs the documented npx tsx ... or npx tsc ... command.
  3. npx resolves the missing package through the configured ...[truncated 1153 chars]
Remediation
View remediation

Remediation Suggestions

Provide a reproducible local toolchain:

  1. Add a package.json containing exact versions of all runtime and development dependencies, including tsx and typescript.
  2. Commit the generated lockfile.
  3. Use a frozen-lockfile installation mode in documented setup instructions.
  4. Invoke only installed local tools:
bash
npx --no-install tsx scan-pools.ts
npx --no-install tsc --noEmit your-script.ts

Alternatively, define package scripts and run them through the package manager:

json
{
  "scripts": {
    "scan-pools": "tsx scan-pools.ts",
    "typecheck": "tsc --noEmit"
  }
}

Additional hardening should include registry allowlisting, package integrity verification, dependency scanning, and running analytics commands without KEYPAIR_PATH in the environment.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (64)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 146)May include surrounding context.

md
#pool-response-key-fields), [Pool Stats](#pool-stats-available-on-every-pool), [examples/scan-pools.md](examples/scan-pools.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1091)May include surrounding context.

md
#pool-response-key-fields), [Pool Stats](#pool-stats-available-on-every-pool), [examples/scan-pools.md](examples/scan-pools.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 155)May include surrounding context.

md
- **Refs**: [examples/compare-fee-tiers.md](examples/compare-fee-tiers.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1093)May include surrounding context.

md
- **Refs**: [examples/compare-fee-tiers.md](examples/compare-fee-tiers.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 174)May include surrounding context.

md
- **Refs**: [Beachhouse API Reference](#beachhouse-api-reference), [examples/stability-rankings.md](examples/stability-rankings.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1095)May include surrounding context.

md
- **Refs**: [Beachhouse API Reference](#beachhouse-api-reference), [examples/stability-rankings.md](examples/stability-rankings.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 186)May include surrounding context.

md
- **Refs**: [examples/lp-range-analysis.md](examples/lp-range-analysis.md), [examples/price-range-history.md](examples/price-range-history.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 535)May include surrounding context.

md
- **Refs**: [examples/lp-range-analysis.md](examples/lp-range-analysis.md), [examples/price-range-history.md](examples/price-range-history.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1096)May include surrounding context.

md
- **Refs**: [examples/lp-range-analysis.md](examples/lp-range-analysis.md), [examples/price-range-history.md](examples/price-range-history.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 186)May include surrounding context.

md
- **Refs**: [examples/lp-range-analysis.md](examples/lp-range-analysis.md), [examples/price-range-history.md](examples/price-range-history.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1098)May include surrounding context.

md
- **Refs**: [examples/lp-range-analysis.md](examples/lp-range-analysis.md), [examples/price-range-history.md](examples/price-range-history.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 201)May include surrounding context.

md
- **Refs**: [examples/range-projection.md](examples/range-projection.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1097)May include surrounding context.

md
- **Refs**: [examples/range-projection.md](examples/range-projection.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 217)May include surrounding context.

md
- **Refs**: [examples/yield-projection.md](examples/yield-projection.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1099)May include surrounding context.

md
- **Refs**: [examples/yield-projection.md](examples/yield-projection.md)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1092)May include surrounding context.

md
| [pool-detail.md](examples/pool-detail.md) | Full breakdown of a single pool |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1094)May include surrounding context.

md
| [pair-discovery.md](examples/pair-discovery.md) | Find all pools for a specific token |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 1100)May include surrounding context.

md
| [monitor-pool.md](examples/monitor-pool.md) | Real-time pool monitoring with price/TVL deltas |

Memory Manipulation

High
Category
Memory Poisoning
Confidence
85% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · examples/swap.md (reported line 140)May include surrounding context.

md
## Notes

- The SDK handles wSOL wrapping/unwrapping automatically for native SOL swaps.
- Slippage is enforced on-chain via `otherAmountThreshold` in the swap instruction.
- The same `swapQuoteByInputToken` + `whirlpool.swap()` pattern works for any token pair that has a Whirlpool.
- For exact-output swaps, use `swapQuoteByOutputToken()` instead.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The manifest-level allowlist includes npx tsx without a fixed version, which creates an avoidable supply-chain and execution-integrity risk. Since tsx is a code runner, compromise or drift in the resolved package could directly alter how generated scripts are interpreted and executed.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding

The manifest-level allowlist includes npx tsx without a fixed version, which creates an avoidable supply-chain and execution-integrity risk. Since tsx is a code runner, compromise or drift in the resolved package could directly alter how generated scripts are interpreted and executed.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The skill manifest permits npx tsx:* without a version pin, which means code execution may depend on whatever tsx version is locally resolved or fetched at runtime. In a skill that generates and runs TypeScript for blockchain operations, that expands the trusted computing base and increases risk of malicious or incompatible tooling being executed.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
92% confidence
Finding

The skill manifest permits npx tsx:* without a version pin, which means code execution may depend on whatever tsx version is locally resolved or fetched at runtime. In a skill that generates and runs TypeScript for blockchain operations, that expands the trusted computing base and increases risk of malicious or incompatible tooling being executed.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
86% confidence
Finding

The documentation instructs users to sanity-check scripts with npx tsc --noEmit, again relying on unpinned runtime tool resolution. Even though this is framed as a safety check, it can still trigger execution of untrusted or drifted toolchain components and weakens reproducibility for a transaction-capable skill.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
94% confidence
Finding

Using npx tsx without pinning a version causes execution of whatever package version is current at runtime, which creates a supply-chain risk. If the package or one of its dependencies is compromised, users following the example could execute attacker-controlled code on their machine.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.