Back to skill

Security audit

hum

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent social-content automation skill, but it needs review because it handles social-account credentials and live account actions and contains real file, network, and dashboard safety weaknesses.

Install only if you are comfortable granting it access to social-account credentials, browser sessions, feed history, drafts, generated images, and outbound provider/API calls. Keep credentials scoped and chmod 600, avoid exposing the local dashboard beyond localhost, do not enable a cron digest until Telegram delivery is explicitly desired, review every publish/follow/reply action before it runs, and treat crawled knowledge sources as untrusted until the path traversal, SSRF, dashboard file-read, environment-forwarding, and dependency-pinning issues are fixed.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (5)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/feed/source/handlers/common.py:33
Finding

Arbitrary Filesystem Writes Through Unsanitized Knowledge Source Keys

Content
View full analysis
Dict[str, str]: """Normalise a parsed row into the source dict handlers expect.""" key = row["key"] handler = row["handler"].lower() url = row["feed url"] name = ( row.get("name") or row.get("source") or row.get("name / source") or key ) author = row.get("author") or name return { "key": key, "name": name, "author": author, "handler": handler, "url": url, } ``` `scripts/feed/source/handlers/common.py:33-39`: ```python def source_dir(source_key: str) -> Path: return KNOWLEDGE_DIR / source_key def images_dir(source_key: str) -> Path: d = source_dir(source_key) / "images" d.mkdir(parents=True, exist_ok=True) return d ``` `scripts/feed/source/handlers/rss.py:19-24,57-63`: ```python def crawl(source: dict, max_articles: int = 0, recrawl: bool = False) -> int: key = source["key"] name = source["name"] author = source["author"] feed_url = source["url"] out_dir = source_dir(key) out_dir.mkdir(parents=True, exist_ok=True) # ... fm = build_frontmatter(title, date, url, key, name, author) dest.write_text(fm + content, encoding="utf-8") saved += 1 ``` ### Technical Analysis The source key is parsed directly from the user-controlled `knowledge/index.md` table and is not constrained to a safe filename format. `pathlib` discards the left operand when the right operand is absolute, and relative components such as `../` are a ...[truncated 1941 chars]
Remediation
View remediation
str: if not SAFE_SOURCE_KEY.fullmatch(value): raise ValueError(f"Invalid source key: {value!r}") return value ``` 2. Resolve every destination and enforce containment: ```python def safe_child(base: Path, *parts: str) -> Path: root = base.resolve() candidate = root.joinpath(*parts).resolve() if not candidate.is_relative_to(root): raise ValueError("Path escapes the configured data directory") return candidate ``` 3. Apply containment checks to article directories, image directories, and final files immediately before directory creation or writing. 4. Reject absolute keys, empty keys, dot components, path separators, and encoded traversal sequences. 5. Avoid overwriting existing files by default. Use exclusive creation or an atomic temporary file followed by a checked rename. 6. Add tests for `../`, absolute paths, repeated separators, symbolic-link escapes, and platform-specific path syntax. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/feed/source/handlers/common.py:117
Finding

Server-Side Request Forgery in Feed and Knowledge Crawlers

Content
View full analysis
int: key = source["key"] name = source["name"] author = source["author"] feed_url = source["url"] out_dir = source_dir(key) out_dir.mkdir(parents=True, exist_ok=True) already = set() if recrawl else existing_urls(key) if already: print(f" {len(already)} articles already saved -- skipping those") feed = feedparser.parse(feed_url) entries = feed.entries if not entries: print(f" ! could not fetch RSS: {feed_url}") return 0 # ... url = entry.get("link", "") if not url or url in already: continue content = extract_article(url, key) ``` `scripts/feed/source/handlers/sitemap.py:17-40`: ```python def fetch_sitemap_urls(sitemap_url: str) -> list: """Fetch and parse a sitemap XML, return flat list of article URLs. Handles both regular sitemaps and sitemap indexes (recurses). """ try: r = requests.get(sitemap_url, headers=HEADERS, timeout=30) if r.status_code != 200: print(f" ! sitemap returned HTTP {r.status_code}: {sitemap_url}") return [] root = ET.fromstring(r.content) ns = {"sm": "http://www.sitemaps.org/schemas/sitemap/0.9"} urls = [] for url_el in root.findall("sm:url", ns): loc = url_el.find("sm:loc", ns) if loc is not None and loc.text: urls.append(loc.text.strip()) for sitemap_el in root.findall("sm:sitemap", ns): loc = sitemap_el.find("sm:lo ...[truncated 3711 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dashboard/serve.py:217
Finding

Local Dashboard Allows Path Traversal and Cross-Origin Data Reads

Content
View full analysis
str | None: """Read a content file by name (supports drafts/ prefix).""" cdir = _CFG["content_dir"] if not cdir: return None path = cdir / filename if path.exists() and path.is_file(): return path.read_text(encoding="utf-8", errors="ignore") return None ``` `scripts/dashboard/serve.py:255-260`: ```python def _read_loop_file(date: str, filename: str) -> str | None: """Read a specific file from a loop run.""" path = _CFG["loop_dir"] / date / filename if path.exists() and path.is_file(): return path.read_text(encoding="utf-8", errors="ignore") return None ``` `scripts/dashboard/serve.py:271-285`: ```python def _json(self, data, status=200): body = json.dumps(data, ensure_ascii=False, default=str).encode("utf-8") self.send_response(status) self.send_header("Content-Type", "application/json; charset=utf-8") self.send_header("Content-Length", str(len(body))) self.send_header("Access-Control-Allow-Origin", "*") self.end_headers() self.wfile.write(body) def _text(self, text, status=200, content_type="text/plain; charset=utf-8"): body = text.encode("utf-8") self.send_response(status) self.send_header("Content-Type", content_type) self.send_header("Content-Length", str(len(body))) self.send_header("Access-Control-Allow-Origin", "*") ``` `scripts/dashboard/serve.py:383-394`: ```python if len(parts) >= 4 and parts[1] == "knowledge" and parts[2] == "article": source_key = parts[3] filename = "/".join(parts[4:]) if len(parts) > 4 else "" if not filename: self._not_found() return pat ...[truncated 2845 chars]
Remediation
View remediation
Path | None: root = base.resolve() candidate = root.joinpath(*parts).resolve() if not candidate.is_relative_to(root): return None if not candidate.is_file(): return None return candidate ``` 2. Reject empty components, dot components, path separators inside a single identifier, absolute paths, and decoded traversal sequences. 3. Use strict allowlist patterns for dates, source keys, and filenames. 4. Do not reconstruct filenames with `"/".join(parts[...])`; route only through indexed file identifiers known to the application. 5. Replace wildcard CORS with either no CORS header or an exact trusted origin. 6. Require an unpredictable per-process session token for API requests. 7. Send defensive headers such as `Content-Security-Policy`, `X-Content-Type-Options: nosniff`, and `Cache-Control: no-store`. 8. Retain the loopback-only bind and document that proxies or tunnels must not expose the dashboard without authentication. 9. Add traversal tests using raw HTTP requests, percent-encoded separators, mixed separators, and symbolic links. ]]>

T02 · Agent Memory Poisoning

Warning
Location
scripts/feed/source/handlers/common.py:150
Finding

Persistent Indirect Prompt Injection Through Automatically Crawled Knowledge

Content
View full analysis
Optional[str]: """Fetch URL, extract clean markdown, optionally download images.""" try: downloaded = trafilatura.fetch_url(url) if not downloaded: return None text = trafilatura.extract( downloaded, include_images=download_images, include_links=False, output_format="markdown", favor_recall=True, ) if not text or len(text) < 200: return None if download_images: text = localise_images(text, source_key) return text ``` `scripts/feed/source/handlers/rss.py:43-63`: ```python url = entry.get("link", "") if not url or url in already: continue title = entry.get("title", "Untitled") date = parse_date(entry) filename = make_filename(date, url) dest = out_dir / filename if not recrawl and dest.exists(): continue print(f" -> {title[:60]}") content = extract_article(url, key) if not content: print(f" skipped (no content extracted)") time.sleep(DELAY) continue fm = build_frontmatter(title, date, url, key, name, author) dest.write_text(fm + content, encoding="utf-8") ``` `SKILL.md:59-61`: ```markdown - **Always read `content-samples/`** before drafting — these are real examples of the user's writing and the most authoritative reference for their voice. - **Always read `knowledge/`** before drafting — any reference material the user has placed there should inform the content. - **Always read `VOICE.md`** for tone and style rules. ``` ### Techni ...[truncated 2293 chars]
Remediation
View remediation
... ``` 3. Stop requiring the agent to read the entire knowledge directory. Select only documents relevant to the current topic and cap the amount of retrieved context. 4. Scan ingested documents for instruction-like language, secret requests, tool directives, role manipulation, and encoded payloads. Flag or quarantine suspicious documents. 5. Preserve source attribution and trust metadata for every document. 6. Separate extracted factual notes from raw source text, while retaining citations for verification. 7. Require user review before newly crawled sources become trusted drafting context. 8. Ensure system and Skill instructions explicitly preserve their priority over retrieved content. ]]>

T08 · Insecure Dependencies

Warning
Location
requirements.txt:1
Finding

Mandatory Setup Installs Mutable Unpinned Dependencies

Content
View full analysis
=6.0 trafilatura>=1.6 lxml_html_clean>=0.1 requests>=2.31 python-slugify>=8.0 youtube-transcript-api>=0.6 # Media download (pin to installed version: yt-dlp --version) yt-dlp>=2024.1.0 ``` `SKILL.md:6`: ```markdown 1. **Init** — `/hum init` sets up the data directory with template files (VOICE.md, CONTENT.md, AUDIENCE.md, CHANNELS.md, knowledge/index.md) and folders. After running init.py, also run `bash setup.sh` from the repo root to create the venv and install Python dependencies. All subsequent scripts require the venv (`venv/bin/python3`). ``` ### Technical Analysis All Python dependencies use lower-bound constraints. Pip may therefore install any future version satisfying the constraint, including major versions that were never reviewed with this Skill. The setup script also upgrades pip without pinning its version. No hash verification is enabled, and no lock file is present. Installation results consequently change over time and across package indexes. Python package installation and import can execute package-supplied code with the user's privileges, making dependency integrity part of the Skill's security boundary. The audited package names appear conventional, and the repository does not specify suspicious third-party indexes or typo-squatted names. This is therefore a supply-chain hardening defect, not evidence that a currently listed package is malicious. ### Attack Path 1. A listed dependen ...[truncated 1015 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • System Prompt LeakageDirect Leakage, Indirect Extraction, Tool-Based Exfiltration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (99)

Tainted flow: 'req' from os.environ.get (line 104, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
94% confidence
Finding

The request URL is built from the OPENAI_BASE_URL environment variable and then used in urllib.request.urlopen with an Authorization header containing the API key. If an attacker can influence the environment, they can redirect the prompt-enhancement request and bearer token to an arbitrary host, causing credential exfiltration and transmission of user prompts to an untrusted endpoint. In an agent/skill context, environment variables are often deployment-controlled, so this is less likely to be intentional malware but still a real security weakness.

Content

Scanner excerpt · scripts/lib/image-gen/generate.py (reported line 111)May include surrounding context.

python
method="POST",
        )

        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode())

        enhanced = data["choices"][0]["message"]["content"].strip()

Tainted flow: 'req' from os.environ.get (line 353, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/lib/image-gen/providers.py (reported line 107)May include surrounding context.

python
)

        try:
            with urllib.request.urlopen(req, timeout=60) as resp:
                data = json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            body = e.read().decode()

Tainted flow: 'req' from os.environ.get (line 353, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/lib/image-gen/providers.py (reported line 206)May include surrounding context.

python
)

        try:
            with urllib.request.urlopen(req, timeout=60) as resp:
                data = json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            body = e.read().decode()

Tainted flow: 'req' from os.environ.get (line 353, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/lib/image-gen/providers.py (reported line 281)May include surrounding context.

python
)

        try:
            with urllib.request.urlopen(req, timeout=60) as resp:
                data = json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            body = e.read().decode()

Tainted flow: 'req' from os.environ.get (line 353, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/lib/image-gen/providers.py (reported line 361)May include surrounding context.

python
)

        try:
            with urllib.request.urlopen(req, timeout=60) as resp:
                data = json.loads(resp.read().decode())
        except urllib.error.HTTPError as e:
            body = e.read().decode()

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 · gemini-extension.json (reported line 20)May include surrounding context.

json
"default": "~/.hum/credentials/"
    },
    {
      "name": "X User Access Token",
      "envVar": "X_USER_ACCESS_TOKEN",
      "description": "X API user access token (overrides credentials file)",
      "sensitive": true

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 · gemini-extension.json (reported line 26)May include surrounding context.

json
"default": "~/.hum/credentials/"
    },
    {
      "name": "X User Access Token",
      "envVar": "X_USER_ACCESS_TOKEN",
      "description": "X API user access token (overrides credentials file)",
      "sensitive": true

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 · gemini-extension.json (reported line 22)May include surrounding context.

json
{
      "name": "X User Access Token",
      "envVar": "X_USER_ACCESS_TOKEN",
      "description": "X API user access token (overrides credentials file)",
      "sensitive": true
    },
    {

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 · gemini-extension.json (reported line 28)May include surrounding context.

json
{
      "name": "X User Access Token",
      "envVar": "X_USER_ACCESS_TOKEN",
      "description": "X API user access token (overrides credentials file)",
      "sensitive": true
    },
    {

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/act/connectors/linkedin.py (reported line 254)May include surrounding context.

python
def _browser_stats(profile_url: str, account: str) -> dict[str, Any]:
    """Return browser scraping instructions for LinkedIn profile stats.

    LinkedIn requires JavaScript rendering, so we return instructions
    for the agent to execute via browser tool. The agent passes the
    extracted data back by calling format_browser_stats().
    """

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
89% confidence
Finding

The code copies the entire process environment and forwards it into Node subprocesses, rather than constructing a narrowly scoped environment. In a skill setting this can leak unrelated secrets present in environment variables to vendored helper scripts, expanding the blast radius if those scripts are compromised, over-privileged, or log their environment.

Content

Scanner excerpt · scripts/lib/bird_x.py (reported line 44)May include surrounding context.

python
def _subprocess_env() -> dict[str, str]:
    env = os.environ.copy()
    env.update(_credentials)
    return env

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill includes an account-modification capability that is not justified by the surrounding search/feed-reading purpose and operates using harvested session credentials. In this context, adding write actions materially increases risk because any caller able to reach this function can cause silent changes to the victim's social graph.

Content

No source excerpt is available for this finding.

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/lib/image-gen/generate.py (reported line 76)May include surrounding context.

python
if not api_key:
        print("[image-gen] No LLM API key for enhancement — using original prompt", file=sys.stderr)
        return prompt

    try:
        system_prompt = (

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/lib/image-gen/generate.py (reported line 120)May include surrounding context.

python
if not api_key:
        print("[image-gen] No LLM API key for enhancement — using original prompt", file=sys.stderr)
        return prompt

    try:
        system_prompt = (

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The scheduled 'Morning Digest' automatically transmits aggregated feed content via Telegram at 6:00am without an explicit per-run user confirmation. Even if intended as a convenience feature, autonomous outbound messaging can leak private reading patterns, curated source data, or account-derived content to external services without sufficiently prominent consent boundaries.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The skill documentation contains a contradictory safety claim: it says to never auto-post to any platform, while elsewhere it defines an automated cron-triggered workflow that sends a Telegram digest. This inconsistency can mislead operators and downstream agents about when outbound communication occurs, increasing the risk of unintended autonomous data transmission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The skill explicitly states that collected and formatted feed content is sent via Telegram, which transmits data off-system to a third-party service. Even if intended behavior, the lack of an explicit warning or consent checkpoint can expose sensitive or copyrighted content gathered from multiple sources, especially when the loop is scheduled to run automatically.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill states that it fetches a user's X home feed, configured sources, knowledge materials, ranks items, and sends a digest to Telegram, but it does not prominently warn that personal feed data and crawled knowledge-source content may be aggregated and transmitted to a third-party messaging service. This creates privacy and data-handling risk because users may unknowingly expose sensitive browsing interests, subscriptions, or proprietary knowledge sources outside the local environment.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill exposes /hum publish and /hum engage as commands that can perform live actions on X and LinkedIn, but the description does not clearly warn users that these commands may post, comment, reply, or follow accounts on their behalf. In an agentic environment, that omission can lead to unintended real-world actions, account misuse, or reputational damage because users may invoke or approve the skill without understanding that external side effects will occur.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The manifest description says only that this is a "Content writing and feed intelligence skill for LinkedIn and X," which is a broad capability statement rather than a specific trigger or constrained invocation condition. Because this is a manifest file and no narrower trigger scope, exclusion conditions, or explicit invocation phrases are provided here, the skill could be matched to common content-help requests too broadly.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The code generates explicit browser-scraping instructions to collect profile metrics and recent post data from X and LinkedIn, but it does not include any user-consent check, privacy notice, or validation that the requested account is authorized for access. In an agent setting, these instructions can trigger network access and data collection from third-party services, which creates privacy, compliance, and platform-terms risks even if the target data is nominally public.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/act/connectors/linkedin.py (reported line 106)May include surrounding context.

python
init_payload = {"initializeUploadRequest": {"owner": author_urn}}
    _, data, _ = http_request(
        "POST",
        "https://api.linkedin.com/rest/images?action=initializeUpload",
        headers=_linkedin_headers(token),
        payload=init_payload,
        exc_factory=ConnectorError,

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · scripts/act/connectors/linkedin.py (reported line 161)May include surrounding context.

python
init_payload = {"initializeUploadRequest": {"owner": author_urn}}
    _, data, _ = http_request(
        "POST",
        "https://api.linkedin.com/rest/images?action=initializeUpload",
        headers=_linkedin_headers(token),
        payload=init_payload,
        exc_factory=ConnectorError,

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The browser-stats path instructs the agent to collect profile analytics such as profile views, post impressions, and search appearances while also stating that 'no login required' and 'publicly visible' data is sufficient. Those metrics are typically non-public and account-scoped, so the instruction can mislead an agent into authenticating or scraping private dashboard information, creating privacy and policy-compliance risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The browser instructions direct collection of follower/connection counts and up to 10 recent posts with engagement metadata, but provide no notice, consent checkpoint, or data-minimization guidance. In an agent setting, that can cause silent collection of personal or account data from LinkedIn pages, increasing privacy and compliance exposure.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access, suspicious.exposed_secret_literal

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/lib/vendor/bird-search/lib/twitter-client-base.js:38

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/lib/vendor/bird-search/bird-search.mjs:96

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
scripts/lib/vendor/bird-search/lib/twitter-client-base.js:19