Back to skill

Security audit

MS Forms Auto

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it stores and reuses Microsoft 365 authentication material in ways users should review carefully before installing.

Install only if you are comfortable giving this skill local access to Microsoft 365 credentials, MFA-assisted sessions, calendar URLs, and organizational form data. Before use, add real gitignore rules, restrict file permissions, avoid passing MFA codes on the command line, remove or disable screenshot/HTML capture, and prefer OAuth or a secure credential store over plaintext passwords.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/submit-with-mfa.js:35
Finding

MFA Codes Are Exposed Through Command-Line Arguments

Content
View full analysis
/cmdline` - Shell history - Cron configuration and execution logs - Process monitoring or endpoint telemetry - Terminal session recording - Wrapper scripts and automation logs Although an MFA code has a short lifetime, the workflow explicitly emphasizes immediate use. A local observer could therefore capture and reuse the code while it remains valid. The exposure is particularly significant when combined with separately compromised M365 credentials. ### Attack Path 1. The user or scheduled workflow runs the submission script with `--code 123456`. 2. A local user, monitoring agent, or log collector records the process arguments. 3. The attacker extracts the MFA code before it expires. 4. If the attacker also possesses the account password or has initiated a matching authentication attempt, the code can be used to complete that attempt. 5. The a ...[truncated 454 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/submit-with-mfa.js:506
Finding

Reusable Browser Session Tokens Are Persisted Without Explicit Access-Control Enforcement

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/login-debug.js:18
Finding

Authenticated and Authentication-Flow Pages Are Saved as Unredacted Screenshots and HTML

Content
View full analysis
{ console.log(` 📸 Saved: ${filename}`); return filepath; }); } function saveHTML(page, filename) { const filepath = path.join(SCREENSHOT_DIR, filename); return page.content().then(html => { fs.writeFileSync(filepath, html.substring(0, 200000)); console.log(` 📄 Saved: ${filename}`); return filepath; }); } ``` The debug flow captures pages throughout authentication: ```javascript await saveScreenshot(page, '03-after-signin.png'); await saveHTML(page, '03-after-signin.html'); // Always capture final state await saveScreenshot(page, '04-final.png'); await saveHTML(page, '04-final.html'); ``` The submission flow also persists the completed page: ```javascript const auditDir = path.join(ROOT_DIR, 'audit-screenshots'); if (!fs.existsSync(auditDir)) fs.mkdirSync(auditDir, { recursive: true }); const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); const auditBase = path.join(auditDir, 'submitted-' + targetDate + '-' + timestamp); await page.screenshot({ path: auditBase + '.png', fullPage: true }); const html = await page.content(); fs.writeFileSync(auditBase + '.html', html.substring(0, 200000)); ``` ### Technical Analysis The Skill saves full-page screenshots and large HTML fragments from l ...[truncated 1846 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/submit-with-mfa.js:554
Finding

Chromium Sandbox Is Disabled Across Authentication and Submission Workflows

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:20
Finding

Documentation Claims Secret Files Are Git-Ignored but No Gitignore Rules Are Present

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (59)

Credential Access

High
Category
Privilege Escalation
Confidence
95% confidence
Finding

The skill instructs creation of config/credentials.json containing M365 email and password, which is direct storage of primary credentials in a local file. Combined with browser automation and stored auth state, this materially increases the chance of credential theft and downstream compromise of corporate Microsoft 365 accounts.

Content

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

node scripts/setup-credentials.js

text

Creates `config/credentials.json` (gitignored) with M365 email/password.

### 3. First Login with MFA

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/calendar-fetch.js # Today (SGT)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/calendar-fetch.js # Today (SGT)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/calendar-fetch.js # Today (SGT)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/calendar-fetch.js # Today (SGT)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/submit-daily.js

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/submit-daily.js

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
node scripts/submit-daily.js

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/submit-with-mfa.js` | **Primary**: Combined MFA login + form submit in one session |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/fill-form.js` | CLI form filler with `--date`, `--training`, etc. args |

Credential Access

High
Category
Privilege Escalation
Confidence
97% confidence
Finding

The configuration table documents multiple local files containing high-value secrets, including M365 credentials, session cookies, and calendar URLs with auth tokens. Even though they are marked gitignored, gitignore does not protect against local compromise, accidental copying, insecure backups, or exposure through logs and support bundles.

Content

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

md
| File | Purpose | Gitignored? |
|------|---------|-------------|
| `config/credentials.json` | M365 email + password | ✅ |
| `config/storageState.json` | Saved browser session (cookies) | ✅ |
| `config/calendars.json` | Calendar URLs (contains auth tokens) | ✅ |
| `config/calendars.json.example` | Template for calendar URLs | ❌ |

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

This instruction explicitly relies on a local file containing valid M365 email/password credentials, normalizing direct credential storage for automated use. Even though the markdown is procedural rather than executable, encouraging use of plaintext or weakly protected credential files materially raises the risk of credential exposure, reuse, or compromise if the workspace, logs, or backups are accessed.

Content

Scanner excerpt · references/TESTING_AUTH_WORKFLOW.md (reported line 18)May include surrounding context.

md
### Prerequisites
- ✅ Skill installed at `~/.openclaw/skills/ms-forms-auto`
- ✅ `config/credentials.json` exists with valid M365 email/password
- ✅ `config/storageState.json` may exist (cached session) or be absent
- ✅ `daily-entries/2026-03-20.json` exists (backfilled entry for testing)

Credential Access

High
Category
Privilege Escalation
Confidence
88% confidence
Finding

Referencing invalid email/password values in config/credentials.json reinforces a pattern where live account credentials are expected to be edited and tested from a file. This is less severe than the prerequisite itself, but it still promotes insecure credential handling practices and may lead users to manipulate real secrets in local files during troubleshooting.

Content

Scanner excerpt · references/TESTING_AUTH_WORKFLOW.md (reported line 117)May include surrounding context.


Test Case 5: Invalid Credentials

Scenario: Wrong email or password in config/credentials.json.

Steps:

bash

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/TESTING_AUTH_WORKFLOW.md (reported line 141)May include surrounding context.

  • To force fresh login for testing, delete config/storageState.json before Test Cases 1-3.
bash
rm /home/ubuntu/.openclaw/workspace/skills/ms-forms-auto/config/storageState.json

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

Referencing a dedicated credentials.json file in a script that automates and diagnoses a Microsoft login flow is a strong credential-access indicator. In skill context, this is more dangerous because the script targets an authentication surface and combines secret-file access with browser automation, a pattern commonly associated with credential harvesting or misuse even if this specific file does not yet submit the credentials.

Content

Scanner excerpt · scripts/diagnose-login.js (reported line 12)May include surrounding context.

js
const ROOT_DIR = path.resolve(path.join(__dirname, '..'));
const CONFIG_DIR = path.join(ROOT_DIR, 'config');
const CREDS_FILE = path.join(CONFIG_DIR, 'credentials.json');
const FORM_URL = 'https://forms.cloud.microsoft/r/LsxLaEv13i';

async function diagnose() {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/login-debug.js (reported line 13)May include surrounding context.

js
const ROOT_DIR = path.join(__dirname, '..');
const CONFIG_DIR = path.join(ROOT_DIR, 'config');
const CREDS_FILE = path.join(CONFIG_DIR, 'credentials.json');
const AUTH_STATE = path.join(CONFIG_DIR, 'storageState.json');
const SCREENSHOT_DIR = path.join(ROOT_DIR, 'screenshots');
const FORM_URL = 'https://forms.cloud.microsoft/r/LsxLaEv13i';

Missing User Warnings

High
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script saves full-page screenshots and raw HTML from authentication flows to disk in a local screenshots directory. Login pages, MFA prompts, error pages, and post-authenticated pages can contain usernames, PII, session-related data, CSRF tokens, or authenticated content, making this a real sensitive-data exposure risk if files are accessed by other users, synced, or committed to source control.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The explicit dependency on a local credentials.json file indicates the skill is designed to obtain account credentials from disk for automated login. In this context, that is a real credential-access pattern because it centralizes sensitive secrets in a predictable file path and combines them with browser automation to access a third-party account.

Content

Scanner excerpt · scripts/mfa-login.js (reported line 20)May include surrounding context.

js
const ROOT_DIR = path.resolve(path.join(__dirname, '..'));
const CONFIG_DIR = path.join(ROOT_DIR, 'config');
const CREDS_FILE = path.join(CONFIG_DIR, 'credentials.json');
const AUTH_STATE = path.join(CONFIG_DIR, 'storageState.json');
const FORM_URL = 'https://forms.cloud.microsoft/r/LsxLaEv13i';

Credential Access

High
Category
Privilege Escalation
Confidence
82% confidence
Finding

This script is explicitly designed to collect and persist a Microsoft 365 email and password in a local JSON file. Storing a primary account password in plaintext on disk creates a credential theft risk from local compromise, backups, malware, or accidental exposure, even if the file is gitignored and mode 600 is requested.

Content

Scanner excerpt · scripts/setup-credentials.js (reported line 4)May include surrounding context.

js
#!/usr/bin/env node
/**
 * Interactive M365 credential setup.
 * Saves email and password to config/credentials.json (gitignored).
 */

const fs = require('fs');

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The dedicated path to credentials.json indicates intentional local secret storage for M365 credentials. Centralizing credentials in a predictable file path increases the chance that other local processes, malware, or users on a shared system can target and harvest the file.

Content

Scanner excerpt · scripts/setup-credentials.js (reported line 12)May include surrounding context.

js
const readline = require('readline');

const CONFIG_DIR = path.join(__dirname, '..', 'config');
const CREDENTIALS_PATH = path.join(CONFIG_DIR, 'credentials.json');

function prompt(question, hidden = false) {
  return new Promise((resolve) => {