T09 · Insecure Skill Coding Practices
Warning
- Location
- src/api.js:12
- Finding
- Caller-Controlled API Origin Can Receive Feishu Bearer Tokens<![CDATA[ ## Vulnerability Details **File Location**: `src/api.js`, lines 12–35 **Vulnerability Type**: Unrestricted authenticated API endpoint configuration **Risk Level**: Medium ### Vulnerable Code ```js this.baseURL = options.baseURL || 'https://open.feishu.cn/open-apis/bitable/v1'; this.accessToken = options.accessToken; this.autoRefreshToken = options.autoRefreshToken !== false; if (!this.appId || !this.appSecret) { throw new Error('缺少FEISHU_APP_ID或FEISHU_APP_SECRET环境变量'); } this.client = axios.create({ baseURL: this.baseURL, timeout: 30000, headers: { 'Content-Type': 'application/json; charset=utf-8' } }); // 请求拦截器:添加认证头 this.client.interceptors.request.use(async (config) => { if (!this.accessToken) { await this.refreshAccessToken(); } config.headers.Authorization = `Bearer ${this.accessToken}`; return config; }); ``` ### Technical Analysis The exported `FeishuBitableAPI` constructor accepts an unrestricted `options.baseURL`. The Axios request interceptor subsequently adds a valid Feishu bearer token to every request sent through the configured client. There is no validation requiring the destination to use HTTPS or belong to the expected `open.feishu.cn` origin. Consequently, a programmatic caller that can influence constructor options can redirect authenticated API requests to an arbitrary server. The bundled CLI does not expose `baseURL`, which reduces direct exploitability through normal command-line usage. However, `src/api.js` is also the package's main exported interface, so applications integrating the package programmatically may pass configuration from environment files, user input, or another untrusted source. ### Attack Path 1. An application imports the package and constructs `FeishuBitableAPI` with externally influenced options. 2. An attacker causes `options.baseURL` to reference an attacker-controlled server. 3. The client obtains a tenant access token using the configured Feishu application ID and s ...[truncated 973 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove support for a configurable API origin if custom Feishu endpoints are not a functional requirement. 2. If endpoint configuration is required, parse the URL and enforce an exact allowlist: - Require the `https:` scheme. - Require the hostname to be exactly `open.feishu.cn`. - Reject embedded credentials, unexpected ports, and look-alike subdomains. 3. Validate the final request URL inside the request interceptor before adding the `Authorization` header. 4. Keep authentication and Bitable API clients separate so that credentials cannot be attached automatically to arbitrary destinations. 5. Reject absolute request URLs that override the configured trusted origin. 6. Add tests proving that bearer tokens are never attached to HTTP requests or requests to unapproved hosts. 7. Ensure applications embedding this library do not populate endpoint options from untrusted input. An appropriate defense-in-depth pattern is: ```js const TRUSTED_ORIGIN = 'https://open.feishu.cn'; const configuredUrl = new URL( options.baseURL || `${TRUSTED_ORIGIN}/open-apis/bitable/v1` ); if ( configuredUrl.protocol !== 'https:' || configuredUrl.origin !== TRUSTED_ORIGIN ) { throw new Error('Untrusted Feishu API endpoint'); } this.client.interceptors.request.use(async (config) => { const finalUrl = new URL(config.url, configuredUrl); if (finalUrl.origin !== TRUSTED_ORIGIN) { throw new Error('Refusing to send credentials to an untrusted origin'); } if (!this.accessToken) { await this.refreshAccessToken(); } config.headers.Authorization = `Bearer ${this.accessToken}`; return config; }); ``` ]]>
