Back to skill

Security audit

OK Computers + Ring Gates + Net Protocol

Security checks for vulnerabilities and agentic risk

Overview

The skill has a coherent blockchain-toolkit purpose, but it includes unsafe remote page loading and powerful transaction/signing workflows that need careful review before installation.

Install only if you are comfortable with a blockchain tool that can prepare and submit permanent public onchain writes. Keep BANKR_API_KEY tightly scoped and do not let an agent submit or sign transactions without reviewing the exact destination, calldata, value, chain, and content. Avoid deploying or visiting net-loader.html as written unless the relay and stored content are trusted and isolated, because it can execute mutable remote/onchain HTML in the page context.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
net-loader.html:35
Finding
<![CDATA[Mutable Remote Code Execution Through JSONP and Untrusted Onchain HTML]]><![CDATA[ ## Vulnerability Details **File Location**: `net-loader.html:35-38`, `net-loader.html:92-104`, and `net-loader.html:116-136` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Complete Vulnerable Code Snippet ```javascript const CONFIG = { storageKey: 'okc-test', // LEFT-padded bytes32 of 'okc-test' keyBytes: '0x0000000000000000000000000000000000000000000000006f6b632d74657374', operator: '0x2460F6C6CA04DD6a73E9B5535aC67Ac48726c09b', // JSONP relay URL - bypasses iframe sandbox! relayUrl: 'https://okc-relay.vercel.app/api/rpc' }; ``` ```javascript // Check if HTML if (data.trim().startsWith('<!DOCTYPE') || data.trim().startsWith('<html')) { document.open(); document.write(data); document.close(); } else { content.textContent = data; } }; // Load content via JSONP relay function loadContent() { const status = document.getElementById('status'); debug('Loading via JSONP relay...'); debug('Key: ' + CONFIG.storageKey); const calldata = buildCalldata(CONFIG.keyBytes, CONFIG.operator); debug('Calldata: ' + calldata.slice(0, 20) + '...'); // Create script tag for JSONP const script = document.createElement('script'); const params = new URLSearchParams({ to: SIMPLE_STORAGE, data: calldata, callback: 'netProtocolCallback', chainId: '8453' }); script.src = CONFIG.relayUrl + '?' + params.toString(); script.onerror = function() { debug('Script load failed - relay might be down'); status.className = 'error'; status.textContent = 'Error: Could not reach relay'; }; debug('Loading: ' + script.src.slice(0, 60) + '...'); document.body.appendChild(script); } ``` The behavior is also explicitly recommended in `SKILL.md:450-454`, which instructs users to deploy the loader so that it retrieves and renders content through the JSONP relay. ### Technical Analysis The loader creates a `<script>` element whose source is a mutable, external ...[truncated 2948 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the JSONP mechanism and the recommendation to bypass iframe network restrictions. 2. Never load RPC data through a `<script>` element. Retrieve it as non-executable data through a controlled API or a narrowly scoped same-origin backend. 3. Authenticate retrieved content before use: - Require a signature from an explicitly trusted publisher. - Bind the signature to the chain ID, contract, key, operator, content hash, and version. - Reject content whose signer or expected hash is not preconfigured. 4. Do not pass untrusted HTML to `document.write()`. Render plain content through `textContent`. 5. If HTML rendering is required, place it in a separate sandboxed iframe without `allow-scripts`, `allow-same-origin`, forms, popups, top navigation, or wallet access. 6. Apply a restrictive Content Security Policy that disallows inline script, event handlers, arbitrary remote scripts, and unexpected network destinations. 7. Pin and independently verify any relay implementation and deployment. A source-code repository reference is not sufficient to authenticate the deployed endpoint. 8. Clearly document that blockchain data is public and untrusted, regardless of whether it passes an integrity hash check. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
medina-dashboard.html:882
Finding
<![CDATA[Stored DOM Cross-Site Scripting in the Medina Dashboard]]><![CDATA[ ## Vulnerability Details **File Location**: `medina-dashboard.html:882-925`, `medina-dashboard.html:966`, and `medina-dashboard.html:993-1030` **Vulnerability Type**: Stored DOM cross-site scripting through unescaped blockchain data **Risk Level**: High ### Complete Vulnerable Code Snippet ```javascript function renderFleet(fleet) { const panel = document.getElementById('fleetPanel'); if (fleet.length === 0) { panel.innerHTML = '<div class="empty-state">No fleet nodes found</div>'; return; } const roles = { 0: 'Gateway (Rocinante)' }; panel.innerHTML = fleet.map((node, i) => { if (node.error) { return `<div class="node"><span class="node-id">#${node.tokenId}</span><span class="node-name" style="color:var(--red)">Error: ${node.error}</span></div>`; } const channelInfo = Object.entries(node.channels).map(([ch, info]) => `${ch.split('_').pop()}: ${info.count} msgs` ).join(', ') || 'No RG channels'; return ` <div class="node"> <span class="status-dot online"></span> <span class="node-id">#${node.tokenId}</span> <span class="node-name">${node.username}</span> <span class="node-role">${roles[i] || 'Fleet Node'}</span> </div> `; }).join(''); } function renderTransmissions(txs) { const panel = document.getElementById('txPanel'); if (txs.length === 0) { panel.innerHTML = '<div class="empty-state">No transmissions detected</div>'; return; } panel.innerHTML = txs.map(tx => ` <div class="transmission"> <div class="tx-header"> <span class="tx-id">TX:${tx.txid}</span> <span class="tx-size">${formatBytes(tx.size)}</span> </div> <div class="tx-progress"><div class="tx-progress-bar" style="width:100%"></div></div> <div class="tx-meta"> <span>${tx.type}</span> <span>${tx.chunks} chunks</span> <span>${tx.sharded ? 'SHARDED' : 'SINGLE'}</span> <span>${tx.hash ? tx.hash.slice(0, 12) + '...' : ''}</s ...[truncated 3824 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace string-based HTML construction with DOM APIs: - Use `document.createElement()`. - Assign all blockchain-derived values through `textContent`. - Set numeric and style properties only after strict type and range validation. 2. Treat all RPC responses, usernames, channel names, manifests, and message fields as untrusted input. 3. If rich formatting is necessary, pass content through a maintained, strict allowlist sanitizer configured to reject scripts, event-handler attributes, SVG, forms, iframes, dangerous URLs, and style-based injection. 4. Validate Ring Gate fields against narrow schemas: - Restrict transaction IDs to four hexadecimal characters. - Restrict message types to the documented enumeration. - Require finite bounded numbers for sizes and chunk counts. - Restrict MIME types to an explicit display-only allowlist. 5. Add a restrictive Content Security Policy that blocks inline handlers and unauthorized script or connection sources. 6. Add regression tests using payloads in usernames and manifest fields, including event handlers, malformed SVG, encoded markup, and hostile channel names. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
okcomputer.js:34
Finding
<![CDATA[Hardcoded Third-Party Alchemy RPC Credential]]><![CDATA[ ## Vulnerability Details **File Location**: `okcomputer.js:34` and `medina-dashboard.html:560` **Vulnerability Type**: Hardcoded service credential in distributed source code **Risk Level**: Medium ### Complete Vulnerable Code Snippet From `okcomputer.js:34`: ```javascript const RPC_URL = "https://base-mainnet.g.alchemy.com/v2/gx18Gx0VA7vJ9o_iYr4VkWUS8GE3AQ1G"; ``` From `medina-dashboard.html:560`: ```javascript const RPC_URL = "https://base-mainnet.g.alchemy.com/v2/gx18Gx0VA7vJ9o_iYr4VkWUS8GE3AQ1G"; ``` The Node.js helper sends calls directly to that endpoint: ```javascript async rpcCall(to, data) { const resp = await fetch(this.rpcUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ jsonrpc: "2.0", method: "eth_call", params: [{ to, data }, "latest"], id: 1, }), }); const result = await resp.json(); if (result.error) throw new Error(`RPC error: ${JSON.stringify(result.error)}`); if (!result.result) throw new Error(`Unexpected RPC response: ${JSON.stringify(result)}`); return result.result; } ``` ### Technical Analysis The Alchemy project identifier is embedded in both the Node.js source and client-side dashboard. Any package recipient or website visitor can extract and reuse it. An RPC project key is not equivalent to a wallet private key and does not directly grant signing authority. Nevertheless, it commonly controls quota, billing attribution, rate limits, telemetry, and access to provider-side project configuration. Publishing it without strict provider restrictions allows unrelated parties to consume the project's resources. Embedding the identifier in browser code makes confidentiality impossible. Even if the key is intended to be public, it must be configured as a deliberately public, narrowly restricted client credential rather than relying on secrecy. ### Attack Path 1. An attacker downloads the project or views the dashboard source. 2. ...[truncated 929 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Revoke or rotate the exposed Alchemy project key. 2. Remove the endpoint from committed source and accept an RPC URL through environment variables or explicit constructor configuration. 3. For browser deployments, use a credential designed to be public and enforce all restrictions available from the provider: - Allowed origins - Allowed chains - Allowed JSON-RPC methods - Per-origin and per-IP rate limits - Spending or quota alerts 4. Prefer a deliberately public, rate-limited Base RPC endpoint for read-only browser functionality where operationally appropriate. 5. Separate development, testing, browser, and production RPC projects so abuse of one key cannot exhaust all environments. 6. Add automated secret scanning to the repository and release pipeline to detect provider keys before distribution. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (39)

Ae1

High
Category
analysis-evasion
Content
- **The `okcomputer.js` helper library** (included in this project)
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Hidden Instructions

High
Category
Prompt Injection
Content
<body>

<div class="container">
  <!-- Header -->
  <div class="header">
    <h1>MEDINA STATION</h1>
    <div class="subtitle">Ring Gates Network Monitor &mdash; OK Computers Inter-System Protocol</div>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
Although framed as loading content, the implementation decodes remote data and, when it looks like HTML, replaces the current document via document.open/document.write/document.close. That means untrusted remote data is not merely displayed but executed as active HTML/JS in the page context, enabling arbitrary script execution, credential theft, UI spoofing, or full takeover of the skill's interface.

Missing User Warnings

High
Confidence
97% confidence
Finding
The skill fetches remote content and injects it into the live document without any warning, consent, or trust boundary. This creates a silent remote-code/content execution path where users cannot distinguish built-in UI from attacker-controlled UI, making phishing, malicious redirects, and deceptive prompts much easier.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The README explicitly recommends bypassing iframe sandbox restrictions through a JSONP relay, which weakens an intended isolation boundary and introduces script-injection and trust-on-relay risks. In this skill context, agents may use the loader to render arbitrary onchain HTML, so a compromised relay or malicious stored content could execute attacker-controlled code in the page context and expose wallet-connected or agent-controlled interactions.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
L188 states that the sandbox blocks 'all network requests' and specifically 'no external scripts.' However, L124-L131 explicitly describe `net-loader.html` using a `<script src=...>` JSONP relay to fetch remote data, which depends on external script loading being allowed. This is an active contradiction in the documentation about the platform's effective capabilities.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The specification exposes a `deploy` command that assembles content from onchain messages and publishes it to a page, but the documentation does not warn that this changes published state or that assembled content may originate from public, potentially untrusted channels. In a protocol centered on reconstructing and deploying blockchain-sourced content, omission of confirmation, provenance checks, and safety warnings increases the chance of accidental defacement or publishing malicious HTML/JS.

Intent-Code Divergence

Medium
Confidence
93% confidence
Finding
The skill claims there are 'No servers. No external dependencies,' but later relies on Bankr APIs and a JSONP relay for core workflows. This is dangerous because it misrepresents the trust boundary and may cause an agent or operator to treat third-party services as unnecessary or safe when they are actually critical external dependencies handling API keys, transaction submission, and content loading.

External Transmission

Medium
Category
Data Exfiltration
Content
**Submit using Bankr's direct API** (recommended — synchronous, instant):

```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"transaction\": $(echo $TX_JSON)}"
Confidence
90% confidence
Finding
The curl example sends a Bankr API key and transaction payload to an external endpoint. This is risky because shell-based examples can encourage unsafe handling of secrets in logs, shell history, process listings, or copied command transcripts while also delegating onchain execution to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
**Submit using Bankr's direct API** (recommended — synchronous, instant):

```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"transaction\": $(echo $TX_JSON)}"
Confidence
90% confidence
Finding
The curl example sends a Bankr API key and transaction payload to an external endpoint. This is risky because shell-based examples can encourage unsafe handling of secrets in logs, shell history, process listings, or copied command transcripts while also delegating onchain execution to a third party.

External Transmission

Medium
Category
Data Exfiltration
Content
**Or submit using Node.js fetch** (no shell commands):

```javascript
const res = await fetch("https://api.bankr.bot/agent/submit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.BANKR_API_KEY,
Confidence
92% confidence
Finding
This skill instructs sending Bankr API keys and transaction objects to an external service via fetch. That is dangerous because the external service becomes a trusted signing/submission intermediary, and any misuse, compromise, or misconfiguration could expose secrets or cause unauthorized onchain actions with real financial impact.

External Transmission

Medium
Category
Data Exfiltration
Content
**Or submit using Node.js fetch** (no shell commands):

```javascript
const res = await fetch("https://api.bankr.bot/agent/submit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.BANKR_API_KEY,
Confidence
92% confidence
Finding
This skill instructs sending Bankr API keys and transaction objects to an external service via fetch. That is dangerous because the external service becomes a trusted signing/submission intermediary, and any misuse, compromise, or misconfiguration could expose secrets or cause unauthorized onchain actions with real financial impact.

External Transmission

Medium
Category
Data Exfiltration
Content
### Submit a Transaction
```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction":{"to":"0x...","data":"0x...","value":"0","chainId":8453}}'
Confidence
89% confidence
Finding
The API reference explicitly recommends external transaction submission to Bankr, which creates a strong trust dependency for transaction integrity and availability. If the endpoint, credentials, or surrounding environment are compromised, users may submit malicious or altered transactions with irreversible onchain consequences.

External Transmission

Medium
Category
Data Exfiltration
Content
### Submit a Transaction
```bash
curl -s -X POST https://api.bankr.bot/agent/submit \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"transaction":{"to":"0x...","data":"0x...","value":"0","chainId":8453}}'
Confidence
89% confidence
Finding
The API reference explicitly recommends external transaction submission to Bankr, which creates a strong trust dependency for transaction integrity and availability. If the endpoint, credentials, or surrounding environment are compromised, users may submit malicious or altered transactions with irreversible onchain consequences.

External Transmission

Medium
Category
Data Exfiltration
Content
### Sign Data (for EIP-712, permits, Seaport orders, etc.)
```bash
curl -s -X POST https://api.bankr.bot/agent/sign \
  -H "X-API-Key: $BANKR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"signatureType":"eth_signTypedData_v4","typedData":{...}}'
Confidence
94% confidence
Finding
The skill documents an external signing endpoint for EIP-712 and other signature types using the Bankr API key. This is especially dangerous because signing authority can approve token transfers, permits, marketplace orders, or other high-impact actions without directly broadcasting a transaction, making abuse harder to notice but potentially financially catastrophic.

External Transmission

Medium
Category
Data Exfiltration
Content
const tx = ok.buildPostMessage("board", "hello from an AI agent!");

// 5. Submit via Bankr direct API
const res = await fetch("https://api.bankr.bot/agent/submit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.BANKR_API_KEY,
Confidence
92% confidence
Finding
The example transmits a transaction to Bankr using an API key from the environment. In the context of an agent skill, this normalizes automated external transaction submission and increases the chance that an agent forwards valuable signing authority or executes irreversible blockchain actions without adequate scrutiny.

External Transmission

Medium
Category
Data Exfiltration
Content
const tx = ok.buildPostMessage("board", "hello from an AI agent!");

// 5. Submit via Bankr direct API
const res = await fetch("https://api.bankr.bot/agent/submit", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.BANKR_API_KEY,
Confidence
92% confidence
Finding
The example transmits a transaction to Bankr using an API key from the environment. In the context of an agent skill, this normalizes automated external transaction submission and increases the chance that an agent forwards valuable signing authority or executes irreversible blockchain actions without adequate scrutiny.

Intent-Code Divergence

Medium
Confidence
89% confidence
Finding
The Ring Gates section states the sandbox blocks all network requests, but the Net Protocol loader later depends on a JSONP relay to fetch content. This contradiction matters because it obscures how network access is actually obtained and can hide the fact that remote content injection and third-party relay trust are part of the design.

External Transmission

Medium
Category
Data Exfiltration
Content
// 2. Submit each via Bankr direct API
for (const tx of txs) {
  const res = await fetch("https://api.bankr.bot/agent/submit", {
    method: "POST",
    headers: {
      "X-API-Key": process.env.BANKR_API_KEY,
Confidence
91% confidence
Finding
This looped submission pattern sends multiple transactions to an external API, amplifying risk because a single logic error or compromise can trigger a batch of irreversible writes. In a blockchain context, repeated automated submissions can rapidly create financial loss, spam, or persistent onchain data publication.

External Transmission

Medium
Category
Data Exfiltration
Content
// 2. Submit each via Bankr direct API
for (const tx of txs) {
  const res = await fetch("https://api.bankr.bot/agent/submit", {
    method: "POST",
    headers: {
      "X-API-Key": process.env.BANKR_API_KEY,
Confidence
91% confidence
Finding
This looped submission pattern sends multiple transactions to an external API, amplifying risk because a single logic error or compromise can trigger a batch of irreversible writes. In a blockchain context, repeated automated submissions can rapidly create financial loss, spam, or persistent onchain data publication.

External Transmission

Medium
Category
Data Exfiltration
Content
const tx = np.buildStore("my-page", "my-page", "<h1>Hello from the blockchain</h1>");

// Submit via Bankr direct API
// curl -X POST https://api.bankr.bot/agent/submit -H "X-API-Key: $BANKR_API_KEY" -d '{"transaction": ...}'
```

### Key Encoding (Important)
Confidence
87% confidence
Finding
The Net Protocol write example again routes transaction submission through Bankr, extending the same external-trust and secret-handling risks to another storage flow. Because this writes persistent blockchain data, mistakes or abuse cannot be easily reversed and may also publish sensitive content permanently.

External Transmission

Medium
Category
Data Exfiltration
Content
const tx = np.buildStore("my-page", "my-page", "<h1>Hello from the blockchain</h1>");

// Submit via Bankr direct API
// curl -X POST https://api.bankr.bot/agent/submit -H "X-API-Key: $BANKR_API_KEY" -d '{"transaction": ...}'
```

### Key Encoding (Important)
Confidence
87% confidence
Finding
The Net Protocol write example again routes transaction submission through Bankr, extending the same external-trust and secret-handling risks to another storage flow. Because this writes persistent blockchain data, mistakes or abuse cannot be easily reversed and may also publish sensitive content permanently.

External Transmission

Medium
Category
Data Exfiltration
Content
const { OKComputer } = require("./okcomputer");

const BANKR_API_KEY = process.env.BANKR_API_KEY;
const BANKR_SUBMIT = "https://api.bankr.bot/agent/submit";
const CHANNEL = "rg_1399_broadcast";
const TOKEN_ID = 1399;
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
const { OKComputer } = require("./okcomputer");

const BANKR_API_KEY = process.env.BANKR_API_KEY;
const BANKR_SUBMIT = "https://api.bankr.bot/agent/submit";
const CHANNEL = "rg_1399_broadcast";
const TOKEN_ID = 1399;
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
const { OKComputer } = require("./okcomputer");

const BANKR_API_KEY = process.env.BANKR_API_KEY;
const BANKR_SUBMIT = "https://api.bankr.bot/agent/submit";
const CHANNEL = "rg_1399_broadcast";
const TOKEN_ID = 1399;
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
first-transmission.js:14