Back to skill

Security audit

RiskOfficer

Security checks across malware telemetry and agentic risk

Overview

This is a legitimate RiskOfficer analytics skill, but it deserves Review because it can use an account-level token to read sensitive portfolio data and perform persistent account changes, including deletes and broker disconnection.

Install only if you trust RiskOfficer with your portfolio data and are comfortable giving this skill an account-level API token. Prefer a session environment variable over storing the token on disk, revoke the token when done, and require explicit confirmation before any create/update/delete, optimization apply, active snapshot change, broker sync, or broker disconnect action, especially when sandbox=false targets a live connection.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (25)

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The README advertises data-changing capabilities such as create, edit, delete portfolios and disconnect brokers, but it does not clearly warn that these actions modify persistent remote state. In an agentic context, a user may phrase exploratory requests ambiguously and the agent could invoke destructive operations without an explicit confirmation boundary, leading to unintended portfolio changes or broker disconnects.

Vague Triggers

Medium
Confidence
78% confidence
Finding
The invocation description is broad enough to trigger this skill for generic portfolio-management requests, including ambiguous 'manage portfolios' actions. That increases the chance the agent routes users into a third-party skill that can read, modify, and delete portfolio data, even when a narrower local or lower-risk workflow might suffice.

External Transmission

Medium
Category
Data Exfiltration
Content
Use this **before creating or editing any portfolio** to validate ticker symbols and get their currency/exchange info. Also use when the user mentions a company name instead of a ticker.

```bash
curl -s "https://api.riskofficer.tech/api/v1/tickers/search?q=Apple&limit=10&locale=en" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
89% confidence
Finding
curl -s "https://api.riskofficer.tech/api/v1/tickers/search?q=Apple&limit=10&locale=en" \ -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" ``` **Query params:** - `q` (optional): search query — by

External Transmission

Medium
Category
Data Exfiltration
Content
When the user wants to run risk calculations on a historical version of their portfolio:

```bash
curl -s -X PATCH "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"portfolio_key": "manual:My Portfolio", "snapshot_id": "{historical_snapshot_id}"}'
Confidence
87% confidence
Finding
curl -s -X PATCH "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot" \ -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \ -H "Content-Type: application/json" \ -d

External Transmission

Medium
Category
Data Exfiltration
Content
#### Reset Active Snapshot to Latest

```bash
curl -s -X DELETE "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot?portfolio_key=manual:My%20Portfolio" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
83% confidence
Finding
curl -s -X DELETE "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot?portfolio_key=manual:My%20Portfolio" \ -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" ``` **User prompt examples:*

External Transmission

Medium
Category
Data Exfiltration
Content
**Requires 200+ trading days of price history per ticker** (backend requests 252 days). If the portfolio has short history, suggest Risk Parity instead.

```bash
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/optimize-calmar" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
88% confidence
Finding
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/optimize-calmar" \ -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \ -H "Content-Type: application/json" \ -d '{

External Transmission

Medium
Category
Data Exfiltration
Content
When the user or AI agent wants to validate a target portfolio before execution. **VaR is computed using historical method** (empirical distribution from market data).

```bash
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/pre-trade-check" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
90% confidence
Finding
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/pre-trade-check" \ -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "target_portfolio"

External Transmission

Medium
Category
Data Exfiltration
Content
### API Base URL

```
https://api.riskofficer.tech/api/v1
```

All requests require: `Authorization: Bearer ${RISK_OFFICER_TOKEN}`
Confidence
86% confidence
Finding
https://api.riskofficer.tech/

External Transmission

Medium
Category
Data Exfiltration
Content
Use this **before creating or editing any portfolio** to validate ticker symbols and get their currency/exchange info. Also use when the user mentions a company name instead of a ticker.

```bash
curl -s "https://api.riskofficer.tech/api/v1/tickers/search?q=Apple&limit=10&locale=en" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
89% confidence
Finding
https://api.riskofficer.tech/

External Transmission

Medium
Category
Data Exfiltration
Content
When the user wants to run risk calculations on a historical version of their portfolio:

```bash
curl -s -X PATCH "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"portfolio_key": "manual:My Portfolio", "snapshot_id": "{historical_snapshot_id}"}'
Confidence
87% confidence
Finding
https://api.riskofficer.tech/

External Transmission

Medium
Category
Data Exfiltration
Content
#### Reset Active Snapshot to Latest

```bash
curl -s -X DELETE "https://api.riskofficer.tech/api/v1/portfolio/active-snapshot?portfolio_key=manual:My%20Portfolio" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
83% confidence
Finding
https://api.riskofficer.tech/

External Transmission

Medium
Category
Data Exfiltration
Content
**Requires 200+ trading days of price history per ticker** (backend requests 252 days). If the portfolio has short history, suggest Risk Parity instead.

```bash
curl -s -X POST "https://api.riskofficer.tech/api/v1/portfolio/{snapshot_id}/optimize-calmar" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
88% confidence
Finding
https://api.riskofficer.tech/

External Transmission

Medium
Category
Data Exfiltration
Content
When the user or AI agent wants to validate a target portfolio before execution. **VaR is computed using historical method** (empirical distribution from market data).

```bash
curl -s -X POST "https://api.riskofficer.tech/api/v1/risk/pre-trade-check" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
90% confidence
Finding
https://api.riskofficer.tech/

Session Persistence

Medium
Category
Rogue Agent
Content
Connects to the RiskOfficer API to manage investment portfolios and calculate financial risk metrics.

**Required:** One environment variable — `RISK_OFFICER_TOKEN` (create in RiskOfficer app → Settings → API Keys). No other env vars or binaries are required.

**Source:** Official skill repository: [github.com/mib424242/riskofficer-openclaw-skill](https://github.com/mib424242/riskofficer-openclaw-skill). Product: [riskofficer.tech](https://riskofficer.tech). The token is issued only by the RiskOfficer app; this skill does not collect or store credentials.
Confidence
91% confidence
Finding
create in RiskOfficer app → Settings → API Keys). No other env vars or binaries are required. **Source:** Official skill repository: [github.com/mib424242/riskofficer-openclaw-skill](https://github.c

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- `sandbox=false` for live connection, `sandbox=true` for sandbox
- Removes the connection and its saved API key; portfolio snapshot **history is preserved**
- To also delete snapshot history, first use `DELETE /portfolio/broker/{broker}?sandbox=false`
- **ALWAYS confirm before disconnecting** — reconnection requires the mobile app

**Difference between the two delete endpoints:**
Confidence
92% confidence
Finding
DELETE /portfolio/broker/{broker}?sandbox=false`

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Difference between the two delete endpoints:**

| Action | DELETE /portfolio/broker/{id} | DELETE /brokers/connections/{id} |
|--------|-------------------------------|----------------------------------|
| Deletes snapshots | ✅ Yes (archives history) | ❌ No (history kept) |
| Deletes connection | ❌ No | ✅ Yes |
Confidence
93% confidence
Finding
DELETE /portfolio/broker/{id}

Tool Parameter Abuse

High
Category
Tool Misuse
Content
**Difference between the two delete endpoints:**

| Action | DELETE /portfolio/broker/{id} | DELETE /brokers/connections/{id} |
|--------|-------------------------------|----------------------------------|
| Deletes snapshots | ✅ Yes (archives history) | ❌ No (history kept) |
| Deletes connection | ❌ No | ✅ Yes |
Confidence
93% confidence
Finding
DELETE /brokers/connections/{id}

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### User wants to delete a portfolio
"Delete my test portfolio" / "Удали портфель 'Тест'"
→ Confirm: "This will permanently delete all N snapshots for 'Test'. Cannot be undone. Continue?"
→ On confirmation: `DELETE /portfolio/manual/Test`
→ Report `archived_snapshots` count

### User wants to disconnect a broker
Confidence
94% confidence
Finding
DELETE /portfolio/manual/Test`

Tool Parameter Abuse

High
Category
Tool Misuse
Content
### User wants to disconnect a broker
"Disconnect Tinkoff" / "Отключи Тинькофф"
→ Confirm: "This will remove the Tinkoff connection. Portfolio history will be kept. Continue?"
→ On confirmation: `DELETE /brokers/connections/tinkoff?sandbox=false`
→ Inform that reconnection requires the mobile app

### User wants Black-Litterman optimization
Confidence
92% confidence
Finding
DELETE /brokers/connections/tinkoff?sandbox=false`

Unsafe Defaults

Medium
Category
Tool Misuse
Content
When the user wants to clear broker portfolio history without disconnecting the broker:

```bash
curl -s -X DELETE "https://api.riskofficer.tech/api/v1/portfolio/broker/tinkoff?sandbox=false" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
88% confidence
Finding
sandbox=false

Unsafe Defaults

Medium
Category
Tool Misuse
Content
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```

- `sandbox=true` for sandbox portfolio, `sandbox=false` for live/production
- Archives snapshots only; broker connection stays active
- Next sync will create a new snapshot
- **ALWAYS confirm before deleting**
Confidence
86% confidence
Finding
sandbox=false

Unsafe Defaults

Medium
Category
Tool Misuse
Content
When the user wants to remove a broker connection:

```bash
curl -s -X DELETE "https://api.riskofficer.tech/api/v1/brokers/connections/tinkoff?sandbox=false" \
  -H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```
Confidence
90% confidence
Finding
sandbox=false

Unsafe Defaults

Medium
Category
Tool Misuse
Content
-H "Authorization: Bearer ${RISK_OFFICER_TOKEN}"
```

- `sandbox=false` for live connection, `sandbox=true` for sandbox
- Removes the connection and its saved API key; portfolio snapshot **history is preserved**
- To also delete snapshot history, first use `DELETE /portfolio/broker/{broker}?sandbox=false`
- **ALWAYS confirm before disconnecting** — reconnection requires the mobile app
Confidence
85% confidence
Finding
sandbox=false

Unsafe Defaults

Medium
Category
Tool Misuse
Content
- `sandbox=false` for live connection, `sandbox=true` for sandbox
- Removes the connection and its saved API key; portfolio snapshot **history is preserved**
- To also delete snapshot history, first use `DELETE /portfolio/broker/{broker}?sandbox=false`
- **ALWAYS confirm before disconnecting** — reconnection requires the mobile app

**Difference between the two delete endpoints:**
Confidence
85% confidence
Finding
sandbox=false

Unsafe Defaults

Medium
Category
Tool Misuse
Content
### User wants to disconnect a broker
"Disconnect Tinkoff" / "Отключи Тинькофф"
→ Confirm: "This will remove the Tinkoff connection. Portfolio history will be kept. Continue?"
→ On confirmation: `DELETE /brokers/connections/tinkoff?sandbox=false`
→ Inform that reconnection requires the mobile app

### User wants Black-Litterman optimization
Confidence
89% confidence
Finding
sandbox=false

VirusTotal

66/66 vendors flagged this skill as clean.

View on VirusTotal