T01 · Skill Instruction Hijacking
- Location
SKILL.md:18- Finding
Forced Promotional Output Through Skill Instruction Hijacking
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This Bazi skill mostly does what it claims, but it overreaches by auto-sending sensitive birth data to external AI services and broadly loading local credential files.
Install only if you are comfortable with birth details and generated Bazi reports being sent to configured DeepSeek/OpenAI-compatible services. Prefer running with --no-interpret for local-only output, avoid running it from directories that contain unrelated .env files, and do not configure custom base URLs unless you fully trust the endpoint.
SKILL.md:18Forced Promotional Output Through Skill Instruction Hijacking
index.js:12Overbroad Loading of the Global OpenClaw Environment File
index.js:183API Credentials Can Be Sent to an Arbitrary Configured Endpoint
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
1. 在技能根目录下创建 `.env` 文件(可以复制示例文件):
```bash
cp .env.example .env
```
2. 编辑 `.env` 文件,填入您的 API Key:
```ini
The declared purpose frames the skill as a local Bazi calculation tool, but the documented behavior includes external API calls, environment/secret loading, local file access, and unrelated third-party promotional output. This mismatch is dangerous because users and orchestrators may invoke the skill under false assumptions, causing unexpected disclosure of sensitive birth data and trust-boundary violations.
The skill defaults to AI interpretation but does not provide a clear user-facing warning that birth date, time, and gender may be sent to external AI providers. Birth data is sensitive personal information, and silent transmission to third parties creates privacy and compliance risk, especially because the interpretation is enabled by default.
The custom .env loader is a credential-access mechanism that reads secrets from disk into process memory, including locations outside the immediate skill directory. While it appears intended to simplify configuration, this behavior gives the skill access to credentials beyond what its core function justifies and materially increases the sensitivity of the execution context.
const __dirname = path.dirname(__filename);
const require = createRequire(import.meta.url);
// Robust .env loader
function loadEnv() {
const paths = [
path.join(process.cwd(), '.env'),
Reading a local .env file from the current working directory can expose unrelated application credentials to this skill, especially if it is run from a shared project folder. That broadens credential access unnecessarily and could enable misuse if other parts of the skill or dependencies later transmit or log environment contents.
// Robust .env loader
function loadEnv() {
const paths = [
path.join(process.cwd(), '.env'),
path.join(__dirname, '.env'),
path.join(os.homedir(), '.openclaw/.env')
];
Reading a .env adjacent to the skill is less concerning than scanning wider locations, but it still constitutes credential access and secret ingestion into memory. This is often legitimate configuration handling, yet it remains sensitive because the skill can then use those secrets for outbound network calls.
function loadEnv() {
const paths = [
path.join(process.cwd(), '.env'),
path.join(__dirname, '.env'),
path.join(os.homedir(), '.openclaw/.env')
];
Reading ~/.openclaw/.env reaches into the user's home directory and may capture credentials unrelated to this specific skill. In the context of a Bazi analysis tool, that capability is disproportionate and dangerous because it expands access to high-value secrets without a clear functional need.
const paths = [
path.join(process.cwd(), '.env'),
path.join(__dirname, '.env'),
path.join(os.homedir(), '.openclaw/.env')
];
for (const envPath of paths) {
The combination of minification, packed data, and generated-style code prevents trustworthy validation of what the skill actually does. For an agent skill, that lack of inspectability is dangerous because reviewers cannot confidently rule out hidden behavior affecting downstream prompts, outputs, or any future-integrated tools.
var BaziSDK=(function(exports){'use strict';var R2=Object.create;var A2=Object.defineProperty;var k2=Object.getOwnPropertyDescriptor;var X2=Object.getOwnPropertyNames;var U2=Object.getPrototypeOf,J2=Object.prototype.hasOwnProperty;var d2=(e,s)=>()=>(s||e((s={exports:{}}).exports,s),s.exports);var $2=(e,s,u,f)=>{if(s&&typeof s=="object"||typeof s=="function")for(let E of X2(s))!J2.call(e,E)&&E!==u&&A2(e,E,{get:()=>s[E],enumerable:!(f=k2(s,E))||f.enumerable});return e};var k0=(e,s,u)=>(u=e!=null?R2(U2(e)):{},$2(!e||!e.__esModule?A2(u,"default",{value:e,enumerable:true}):u,e));var D2=d2((p2,M0)=>{(function(e,s){if(typeof define=="function"&&define.amd)define(s);else if(typeof M0<"u"&&M0.exports)M0.exports=s();else {var u=s();for(var f in u)e[f]=u[f];}})(p2,function(){var e=(function(){var o=function(h){return r(h.getFullYear(),h.getMonth()+1,h.getDate(),h.getHours(),h.getMinutes(),h.getSeconds())},n=function(h){var d=Math.floor(h+.5),p=h+.5-d,I;d>=2299161&&(I=Math.floor((d-186721625e-2)/36524.25),d+=1+I-Math.floor(I/4)),d+=1524;var G=Math.floor((d-122.1)/365.25);d-=Math.floor(365.25*G);var x=Math.floor(d/30.601);d-=Math.floor(30.601*x);var T=d;x>13?(x-=13,G-=4715):(x-=1,G-=4716),p*=24;var v=Math.floor(p);p-=v,p*=60;var j=Math.floor(p);p-=j,p*=60;var m=Math.round(p);return m>59&&(m-=60,j++),j>59&&(j-=60,v++),v>23&&(v-=24,T+=1),r(G,x,T,v,j,m)},r=function(h,d,p,I,G,x){var T=h,v=d,j=p,m=I,z=G,M=x;if(h*=1,isNaN(h))throw new Error("wrong solar year "+T);if(d*=1,isNaN(d))throw new Error("wrong solar month "+v);if(p*=1,isNaN(p))throw new Error("wrong solar day "+j);if(I*=1,isNaN(I))throw new Error("wrong hour "+m);if(G*=1,isNaN(G))throw new Error("wrong minute "+z);if(x*=1,isNaN(x))throw new Error("wrong second "+M);if(h===1582&&d===10&&p>4&&p<15)throw new Error("wrong solar year "+h+" month "+d+" day "+p);if(d<1||d>12)throw new Error("wrong month "+d);if(p<1||p>31)throw new Error("wrong day "+p);if(I<0||I>23)throw new Error("wrong hour "+I);if(G<0||G>59)throw new Error("wrong
...[truncated 28 chars]
The combination of minification, packed data, and generated-style code prevents trustworthy validation of what the skill actually does. For an agent skill, that lack of inspectability is dangerous because reviewers cannot confidently rule out hidden behavior affecting downstream prompts, outputs, or any future-integrated tools.
var BaziSDK=(function(exports){'use strict';var R2=Object.create;var A2=Object.defineProperty;var k2=Object.getOwnPropertyDescriptor;var X2=Object.getOwnPropertyNames;var U2=Object.getPrototypeOf,J2=Object.prototype.hasOwnProperty;var d2=(e,s)=>()=>(s||e((s={exports:{}}).exports,s),s.exports);var $2=(e,s,u,f)=>{if(s&&typeof s=="object"||typeof s=="function")for(let E of X2(s))!J2.call(e,E)&&E!==u&&A2(e,E,{get:()=>s[E],enumerable:!(f=k2(s,E))||f.enumerable});return e};var k0=(e,s,u)=>(u=e!=null?R2(U2(e)):{},$2(!e||!e.__esModule?A2(u,"default",{value:e,enumerable:true}):u,e));var D2=d2((p2,M0)=>{(function(e,s){if(typeof define=="function"&&define.amd)define(s);else if(typeof M0<"u"&&M0.exports)M0.exports=s();else {var u=s();for(var f in u)e[f]=u[f];}})(p2,function(){var e=(function(){var o=function(h){return r(h.getFullYear(),h.getMonth()+1,h.getDate(),h.getHours(),h.getMinutes(),h.getSeconds())},n=function(h){var d=Math.floor(h+.5),p=h+.5-d,I;d>=2299161&&(I=Math.floor((d-186721625e-2)/36524.25),d+=1+I-Math.floor(I/4)),d+=1524;var G=Math.floor((d-122.1)/365.25);d-=Math.floor(365.25*G);var x=Math.floor(d/30.601);d-=Math.floor(30.601*x);var T=d;x>13?(x-=13,G-=4715):(x-=1,G-=4716),p*=24;var v=Math.floor(p);p-=v,p*=60;var j=Math.floor(p);p-=j,p*=60;var m=Math.round(p);return m>59&&(m-=60,j++),j>59&&(j-=60,v++),v>23&&(v-=24,T+=1),r(G,x,T,v,j,m)},r=function(h,d,p,I,G,x){var T=h,v=d,j=p,m=I,z=G,M=x;if(h*=1,isNaN(h))throw new Error("wrong solar year "+T);if(d*=1,isNaN(d))throw new Error("wrong solar month "+v);if(p*=1,isNaN(p))throw new Error("wrong solar day "+j);if(I*=1,isNaN(I))throw new Error("wrong hour "+m);if(G*=1,isNaN(G))throw new Error("wrong minute "+z);if(x*=1,isNaN(x))throw new Error("wrong second "+M);if(h===1582&&d===10&&p>4&&p<15)throw new Error("wrong solar year "+h+" month "+d+" day "+p);if(d<1||d>12)throw new Error("wrong month "+d);if(p<1||p>31)throw new Error("wrong day "+p);if(I<0||I>23)throw new Error("wrong hour "+I);if(G<0||G>59)throw new Error("wrong
...[truncated 28 chars]
The combination of minification, packed data, and generated-style code prevents trustworthy validation of what the skill actually does. For an agent skill, that lack of inspectability is dangerous because reviewers cannot confidently rule out hidden behavior affecting downstream prompts, outputs, or any future-integrated tools.
var BaziSDK=(function(exports){'use strict';var R2=Object.create;var A2=Object.defineProperty;var k2=Object.getOwnPropertyDescriptor;var X2=Object.getOwnPropertyNames;var U2=Object.getPrototypeOf,J2=Object.prototype.hasOwnProperty;var d2=(e,s)=>()=>(s||e((s={exports:{}}).exports,s),s.exports);var $2=(e,s,u,f)=>{if(s&&typeof s=="object"||typeof s=="function")for(let E of X2(s))!J2.call(e,E)&&E!==u&&A2(e,E,{get:()=>s[E],enumerable:!(f=k2(s,E))||f.enumerable});return e};var k0=(e,s,u)=>(u=e!=null?R2(U2(e)):{},$2(!e||!e.__esModule?A2(u,"default",{value:e,enumerable:true}):u,e));var D2=d2((p2,M0)=>{(function(e,s){if(typeof define=="function"&&define.amd)define(s);else if(typeof M0<"u"&&M0.exports)M0.exports=s();else {var u=s();for(var f in u)e[f]=u[f];}})(p2,function(){var e=(function(){var o=function(h){return r(h.getFullYear(),h.getMonth()+1,h.getDate(),h.getHours(),h.getMinutes(),h.getSeconds())},n=function(h){var d=Math.floor(h+.5),p=h+.5-d,I;d>=2299161&&(I=Math.floor((d-186721625e-2)/36524.25),d+=1+I-Math.floor(I/4)),d+=1524;var G=Math.floor((d-122.1)/365.25);d-=Math.floor(365.25*G);var x=Math.floor(d/30.601);d-=Math.floor(30.601*x);var T=d;x>13?(x-=13,G-=4715):(x-=1,G-=4716),p*=24;var v=Math.floor(p);p-=v,p*=60;var j=Math.floor(p);p-=j,p*=60;var m=Math.round(p);return m>59&&(m-=60,j++),j>59&&(j-=60,v++),v>23&&(v-=24,T+=1),r(G,x,T,v,j,m)},r=function(h,d,p,I,G,x){var T=h,v=d,j=p,m=I,z=G,M=x;if(h*=1,isNaN(h))throw new Error("wrong solar year "+T);if(d*=1,isNaN(d))throw new Error("wrong solar month "+v);if(p*=1,isNaN(p))throw new Error("wrong solar day "+j);if(I*=1,isNaN(I))throw new Error("wrong hour "+m);if(G*=1,isNaN(G))throw new Error("wrong minute "+z);if(x*=1,isNaN(x))throw new Error("wrong second "+M);if(h===1582&&d===10&&p>4&&p<15)throw new Error("wrong solar year "+h+" month "+d+" day "+p);if(d<1||d>12)throw new Error("wrong month "+d);if(p<1||p>31)throw new Error("wrong day "+p);if(I<0||I>23)throw new Error("wrong hour "+I);if(G<0||G>59)throw new Error("wrong
...[truncated 28 chars]
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).
-6,15.218425,2113731271005e-6,15.218515671,2120670840263e-6,15.218425,2123973309063e-6,15.218425,2125068997336e-6,15.218477932,2136026312633e-6,15.218472436,2156099495538e-6,15.218425,2159021324663e-6,15.218425,2162308575254e-6,15.218461742,2178485706538e-6,15.218425,2178759662849e-6,15.218445786,21853340208e-4,15.218425,2187525481425e-6,15.218425,2188621191481e-6,15.218437494,232214776e-2],QB:o("FrcFs22AFsckF2tsDtFqEtF1posFdFgiFseFtmelpsEfhkF2anmelpFlF1ikrotcnEqEq2FfqmcDsrFor22FgFrcgDscFs22FgEeFtE2sfFs22sCoEsaF2tsD1FpeE2eFsssEciFsFnmelpFcFhkF2tcnEqEpFgkrotcnEqrEtFermcDsrE222FgBmcmr22DaEfnaF222sD1FpeForeF2tssEfiFpEoeFssD1iFstEqFppDgFstcnEqEpFg11FscnEqrAoAF2ClAEsDmDtCtBaDlAFbAEpAAAAAD2FgBiBqoBbnBaBoAAAAAAAEgDqAdBqAFrBaBoACdAAf1AACgAAAeBbCamDgEifAE2AABa1C1BgFdiAAACoCeE1ADiEifDaAEqAAFe1AcFbcAAAAAF1iFaAAACpACmFmAAAAAAAACrDaAAADG0"),SHUO_KB:[1457698231017e-6,29.53067166,1546082512234e-6,29.53085106,16406407353e-4,29.5306,1642472151543e-6,29.53085439,16834305093e-4,29.53086148,1752148041079e
The README instructs users to configure third-party AI services for interpretation but does not clearly disclose that highly sensitive personal data such as birth date, time, and gender may be transmitted to DeepSeek or OpenAI. Because this skill handles personal profiling inputs, the omission creates a meaningful privacy and consent risk even if the transmission is expected by the implementation.
The skill declares code capabilities that can access environment variables and the network, but it does not define any explicit tool scope or permission boundaries. In practice this increases attack surface because the skill can transmit user-provided birth data and use secrets without clear least-privilege constraints or user-visible authorization boundaries.
The invocation description includes broad trigger phrases like 'fortune telling' and 'interpret bazi', which may overlap with ordinary conversation and cause over-invocation. In this skill, over-invocation is more concerning because default behavior can trigger external AI interpretation and data transmission without a strong narrowing condition.
The skill states that it automatically performs AI interpretation by default, which means the agent may make autonomous decisions to invoke an external model and generate substantive fortune-analysis content without explicit user confirmation. This is risky because it combines automatic data sharing with nondeterministic model output and reduces user control over whether cloud interpretation occurs.
## CRITICAL INSTRUCTION FOR AGENT
**This tool automatically performs AI interpretation by default.**
You do NOT need to add `--interpret` flag anymore, unless you want to force it.
If the user wants raw data only, use `--no-interpret`.
The tool contains a specialized DeepSeek prompt that follows 《子平真诠》; you should prefer this over your own interpretation.
The skill is configured to send data to external OpenAI endpoints as a fallback for interpretation. External transmission is not inherently malicious, but in this context it becomes a security/privacy issue because sensitive birth data may be sent off-platform and the behavior is not clearly surfaced as an explicit consented action.
Fallback Configuration (OpenAI):
- `OPENAI_API_KEY`: Used if DeepSeek key is missing.
- `OPENAI_BASE_URL`: Optional, defaults to `https://api.openai.com/v1`.
## Output
The skill proactively loads secrets from multiple filesystem locations, including the user's home directory, even though Bazi analysis does not require broad credential discovery. This increases the skill's access to sensitive tokens and expands the blast radius if the skill is modified, compromised, or logs/transmits configuration unexpectedly.
The system prompt is written entirely in Chinese and mandates a fixed Chinese response structure, while other user-facing strings in the file are also Chinese-only. This imposes a specific language/locale behavior without any documented user opt-in or configurable language selection.
This code transmits user-provided and derived data to an external service endpoint, which is a real data exposure boundary. External transmission is expected for an LLM-backed feature, but it remains security-relevant because the skill handles sensitive personal inputs and does not sufficiently constrain or transparently disclose that transfer.
if (!apiKey) {
apiKey = process.env.OPENAI_API_KEY;
if (apiKey) {
baseURL = process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1';
model = process.env.OPENAI_MODEL || 'gpt-4o';
}
}
The code sends highly sensitive personal data—birth date/time, gender, and derived profile information—to an external LLM API without an explicit just-in-time disclosure or consent step. For a fortune-telling skill, this data is especially privacy-sensitive because it reveals intimate personal attributes and inferred interpretations, creating confidentiality and compliance risk.
The I18n module initializes the active language to "chs" and immediately applies that locale by default, causing outputs and labels to be Chinese unless the caller explicitly changes it. This is a natural-language locale policy concern because the file enforces a specific language choice rather than offering neutral or opt-in behavior by default.
The manifest describes a professional Bazi analysis skill, which justifies computing pillars and interpreting Bazi structures. However, this file also hardcodes extensive domain-specific guidance systems for workplace, wealth, relationships, healing, influence, and life strategy, then exports functions such as calculateYearlyFortunes, calculateMonthlyFortunes, calculateDailyFortunes, calculateHourlyFortunes, getEGActionGuidance, and getEGState that go beyond core chart calculation into prescriptive fortune/lifestyle coaching.
Large embedded guidance maps define recommended and prohibited actions plus risk narratives for many scenarios such as workplace communication, project execution, wealth decisions, intimacy, self-management, healing, influence building, and life strategy. This is a separate coaching capability layered on top of astrology computation, and it is not obviously required just to calculate or interpret Bazi.
The package description is entirely in Chinese and presents the skill in that language with no indication that users can choose another language or locale. Per the policy, forcing a specific language without user opt-in is a natural-language policy concern.
The note recommends DeepSeek specifically for the 'best Chinese metaphysics interpretation effect,' which signals a language/locale preference in the skill's behavior or expected output. Because the README does not explicitly offer users a choice of output language, this can be a natural-language locale policy concern.
Detected: suspicious.env_credential_access