T09 · Insecure Skill Coding Practices
- Location
references/templates/local-testing.md:145- Finding
Debugging Template Logs Credentials and Sensitive Workflow Data in Plaintext
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a documentation-only skill for building n8n community nodes, with expected credential, HTTP, testing, and publishing guidance, but users should avoid copying unsafe debug logging and should tighten dependency versions.
Install is reasonable for n8n community-node development. Before copying examples into a real project, remove full credential/object logging, avoid logging workflow data, use bounded dependency versions and lockfiles, and review any generated node code before publishing to npm or connecting production credentials.
references/templates/local-testing.md:145Debugging Template Logs Credentials and Sensitive Workflow Data in Plaintext
references/templates/project-files.md:63Wildcard Dependency Versions Permit Unreviewed Package Resolution
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
required: true,
},
{
displayName: 'Access Token URL',
name: 'accessTokenUrl',
type: 'hidden',
default: 'https://auth.myservice.com/oauth/token',
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
required: true,
},
{
displayName: 'Access Token URL',
name: 'accessTokenUrl',
type: 'hidden',
default: 'https://auth.myservice.com/oauth/token',
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
required: true,
},
{
displayName: 'Access Token URL',
name: 'accessTokenUrl',
type: 'hidden',
default: 'https://auth.myservice.com/oauth/token',
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
required: true,
},
{
displayName: 'Access Token URL',
name: 'accessTokenUrl',
type: 'hidden',
default: 'https://auth.myservice.com/oauth/token',
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
required: true,
},
{
displayName: 'Access Token URL',
name: 'accessTokenUrl',
type: 'hidden',
default: 'https://auth.myservice.com/oauth/token',
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
const credentials = await this.getCredentials('myServiceOAuth2Api');
// Access token (after automatic refresh if needed)
const tokenData = credentials.oauthTokenData as {
access_token: string;
token_type: string;
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
});
> ⚠️ Do not cache the access token across executions — always read from `getCredentials()` to ensure you get the refreshed token.
---
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.
state.lastRun = new Date().toISOString();
// Reset (useful for testing) delete state.cursor;
> ⚠️ `getWorkflowStaticData('global')` is shared across all nodes in the workflow. `getWorkflowStaticData('node')` is scoped to this node instance — use 'node' unless you specifically need cross-node sharing.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
node_modules/ dist/ *.js.map .env
> Note: Some projects commit `dist/` so users can install from GitHub without building. Either approach is fine — just be consistent.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### Option B: NPM Token (traditional)
1. Go to npmjs.com → Access Tokens → Generate New Token → Granular Access Token
2. Give it publish access to your package
3. Copy the token
4. In GitHub: repo Settings → Secrets → Actions → New repository secret
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
### Option B: NPM Token (traditional)
1. Go to npmjs.com → Access Tokens → Generate New Token → Granular Access Token
2. Give it publish access to your package
3. Copy the token
4. In GitHub: repo Settings → Secrets → Actions → New repository secret
The activation description is very broad and includes many generic terms and full-lifecycle triggers, which can cause the skill to activate in contexts that are only loosely related to building n8n community nodes. Over-triggering can route unrelated user requests into a powerful packaging/publishing skill, increasing the chance of inappropriate guidance, accidental misuse, or prompt-scope confusion.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
const response = await this.helpers.httpRequest({
// ── Required ─────────────────────────────────────────────────
method: 'POST', // GET | POST | PUT | PATCH | DELETE | HEAD
url: 'https://api.example.com/items', // full URL, OR use baseURL + url separately
// ── Optional ─────────────────────────────────────────────────
baseURL: 'https://api.example.com', // if using relative url below
Detected: suspicious.exposed_secret_literal