T09 · Insecure Skill Coding Practices
- Location
scripts/run-sql.mjs:132- Finding
Incomplete read-only SQL enforcement permits database-side effects
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill has a legitimate database-reporting purpose, but it needs review because it handles live Oracle credentials and local files with weak controls.
Review before installing. Use only a dedicated least-privilege read-only Oracle account, avoid passing passwords in chat or command-line flags, avoid sync-env unless file permissions and cleanup are controlled, keep output paths inside the skill output directory, and do not enable persistent memory for ERP data unless you have a retention policy.
scripts/run-sql.mjs:132Incomplete read-only SQL enforcement permits database-side effects
scripts/run-sql.mjs:167User-controlled output paths permit arbitrary file overwrite
PROMPTS.md:35Database credentials are exposed through command-line arguments and insufficiently protected files
scripts/setup.mjs:42Mandatory setup installs mutable dependencies without a lockfile
AGENTS.md:11Skill instructions encourage uncontrolled persistence of user and ERP activity data
This instruction directs the agent to access and potentially create a .env-backed credential store using supplied DB secrets, which is a genuine credential-handling risk. In the context of an agent workspace, secrets written to disk may be exposed to logs, other processes, future tasks, or repository operations, making the risk more serious than ordinary local command usage.
2. Read references/table-reference.md or table-index.md as needed for correct table and column names.
3. **You** choose the read-only Oracle SQL (SELECT or WITH only) that answers ${QUESTION}. Use FETCH FIRST 50 ROWS ONLY unless a count or aggregate alone is enough.
4. Run the query (cross-platform):
- If .env is not set: node scripts/sync-db-env.mjs --db-user="${DB_USER}" --db-password="${DB_PASSWORD}" --db-connect-string="${DB_CONNECT_STRING}"
- Then: npm run sql:save -- "<your SELECT here>"
- Or one shot: node scripts/run-sql.mjs --db-user=... --db-password=... --db-connect-string=... -o output/last-query.json "<your SELECT>"
5. Read output/last-query.json and reply with:
The code defines a workspace .env path and later writes DB_USER, DB_PASSWORD, and DB_CONNECT_STRING into it, creating a persistent plaintext secret store inside the project directory. In this skill context, Oracle credentials are powerful and likely grant access to live enterprise data, so local persistence increases the blast radius if the workspace is shared, indexed, backed up, or committed.
import path from 'path';
import { SKILL_ROOT } from './lib/paths.mjs';
const ENV_PATH = path.join(SKILL_ROOT, '.env');
const FLAG_MAP = {
'--db-user': 'DB_USER',
The prompt directs the agent to handle live Oracle credentials, including writing them into a workspace .env file via sync-db-env.mjs or passing them on the command line. Even though it says not to print secrets, storing or passing credentials this way increases exposure through shell history, process listings, workspace files, logs, and accidental reuse by other tools in the same environment.
2. Read references/table-reference.md or table-index.md as needed for correct table and column names.
3. **You** choose the read-only Oracle SQL (SELECT or WITH only) that answers ${QUESTION}. Use FETCH FIRST 50 ROWS ONLY unless a count or aggregate alone is enough.
4. Run the query (cross-platform):
- If .env is not set: node scripts/sync-db-env.mjs --db-user="${DB_USER}" --db-password="${DB_PASSWORD}" --db-connect-string="${DB_CONNECT_STRING}"
- Then: npm run sql:save -- "<your SELECT here>"
- Or one shot: node scripts/run-sql.mjs --db-user=... --db-password=... --db-connect-string=... -o output/last-query.json "<your SELECT>"
5. Read output/last-query.json and reply with:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cd path/to/simpleerp-db-clean
npm install
cp .env.example .env
# Edit .env
npm run setup
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const REQUIRED_ENV = ['DB_USER', 'DB_PASSWORD', 'DB_CONNECT_STRING'];
function loadDotenv() {
const envPath = path.join(SKILL_ROOT, '.env');
if (!fs.existsSync(envPath)) return;
for (const line of fs.readFileSync(envPath, 'utf8').split(/\r?\n/)) {
const m = line.match(/^([A-Z_]+)=(.*)$/);
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
/**
* Write or update DB_* lines in workspace .env from CLI flags or process.env.
* Cross-platform alternative to shell-specific $env: / export syntax.
*
* Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
/**
* Write or update DB_* lines in workspace .env from CLI flags or process.env.
* Cross-platform alternative to shell-specific $env: / export syntax.
*
* Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
/**
* Write or update DB_* lines in workspace .env from CLI flags or process.env.
* Cross-platform alternative to shell-specific $env: / export syntax.
*
* Usage:
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
/**
* Write or update DB_* lines in workspace .env from CLI flags or process.env.
* Cross-platform alternative to shell-specific $env: / export syntax.
*
* Usage:
Detected: suspicious.dangerous_exec