# How the Hiring-Agent Handles Security: Implementation Guide for the InterviewStreet Repository

> Discover how the hiring agent secures your data through environment variable isolation and input sanitization. Learn about GitHub API rate limits and LLM interaction controls.

- Repository: [HackerRank/hiring-agent](https://github.com/interviewstreet/hiring-agent)
- Tags: how-to-guide
- Published: 2026-07-12

---

**The hiring-agent handles security through environment-variable isolation for secrets, proactive GitHub API rate-limit management, strict input sanitization with whitelist patterns, local response caching, and controlled LLM interaction with client-side deduplication.**

The `interviewstreet/hiring-agent` repository implements a comprehensive defensive strategy to protect sensitive credentials and ensure reliable operation when interacting with external services. Understanding how the hiring-agent handles security is essential for safely deploying this tool in production environments where API keys and tokens must remain protected.

## Environment Variable Isolation

The system never hard-codes sensitive values such as the Gemini API key or GitHub token. Instead, the code loads these secrets at runtime from a `.env` file or the host environment using `dotenv.load_dotenv()`, falling back to empty strings when variables are missing.

In [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py) (lines 8‑12 and 66‑68), the implementation uses `os.getenv()` to safely retrieve credentials:

```python
from dotenv import load_dotenv
import os

load_dotenv()                         # ⇢ reads .env without exposing its path

GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "")
GITHUB_TOKEN   = os.getenv("GITHUB_TOKEN")

```

This pattern ensures that **secrets never ship with the codebase** and remain isolated from version control.

## GitHub API Authentication and Rate Limit Defense

When a `GITHUB_TOKEN` is present, the request header is enriched with `Authorization: token …` in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 30‑34). If the token is absent, the tool operates unauthenticated within the public rate limit of 60 requests per hour.

The code implements proactive rate-limit awareness by inspecting the `X‑RateLimit‑Remaining` and `X‑RateLimit‑Limit` headers after each call. As implemented in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 55‑61 and 67‑95), the system logs the remaining quota and sleeps proactively when thresholds drop below safe limits:

```python
def _fetch_github_api(api_url, params=None):
    headers = {}
    if GITHUB_TOKEN:
        headers["Authorization"] = f"token {GITHUB_TOKEN}"
    response = requests.get(api_url, params=params, headers=headers, timeout=10)
    
    # Rate limit defense

    remaining = int(response.headers.get("X-RateLimit-Remaining", 0))
    reset_ts  = int(response.headers.get("X-RateLimit-Reset", 0))
    
    if remaining < 10:
        wait = max(0, reset_ts - int(time.time())) + 5   # safety buffer

        time.sleep(min(wait, 3600))                     # cap at 1 hour

    return response

```

This **proactive throttling** prevents service bans and ensures continuous operation.

## Input Sanitization and URL Validation

The helper function `extract_github_username` in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 16‑28) implements strict whitelist-based validation. It strips whitespace, normalizes the URL, and only accepts characters matching specific patterns before using the value in API requests.

The validation logic uses regular expressions to match only valid GitHub username formats:

```python
import re
from typing import Optional

def extract_github_username(github_url: str) -> Optional[str]:
    patterns = [
        r"https?://github\.com/([^/]+)",
        r"github\.com/([^/]+)",
        r"@([^/]+)",
        r"^([a-zA-Z0-9-]+)$",
    ]
    for pat in patterns:
        m = re.search(pat, github_url.strip())
        if m:
            return m.group(1).split("?", 1)[0]   # strip query string

    return None

```

This **whitelist approach** prevents injection attacks and ensures only well-formed usernames reach the GitHub API.

## Local Caching for Resilience

When `DEVELOPMENT_MODE` is enabled (defined in [`config.py`](https://github.com/interviewstreet/hiring-agent/blob/main/config.py) lines 5‑6), all GitHub API responses are cached under the `cache/` folder. As implemented in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 104‑110), this reduces external network traffic and limits exposure to quota exhaustion:

```python
if DEVELOPMENT_MODE and status_code == 200:
    os.makedirs("cache", exist_ok=True)
    Path(cache_filename).write_text(
        json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8"
    )

```

Caching ensures the system remains functional even when external services are unavailable, effectively creating a **circuit breaker** against denial-of-service vectors.

## Controlled LLM Interaction

The system constrains LLM outputs through explicit system prompts and client-side validation. In [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 81‑84), the system prompt explicitly instructs the model to avoid duplicates by selecting "exactly 7 UNIQUE projects."

Following the LLM response, the code deduplicates results in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 100‑108) before downstream processing:

```python

# System prompt forces uniqueness

system_msg = {
    "role": "system",
    "content": "You must select exactly 7 UNIQUE projects..."
}

# After LLM response, deduplicate locally

seen = set()
unique = []
for proj in selected_projects:
    name = proj.get("name")
    if name and name not in seen:
        unique.append(proj)
        seen.add(name)

```

This **dual-layer control** ensures policy constraints are enforced regardless of model behavior.

## Safe Logging Architecture

The project centralizes logging through an abstraction defined in [`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py), ensuring that secret values never interpolate into log messages. In [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (line 59), the logger records rate limit status without exposing tokens:

```python
logger.info(f"Rate limit remaining: {remaining}")

```

This architecture prevents **accidental credential leakage** into stdout or log files.

## Summary

The hiring-agent implements a defense-in-depth strategy that:

- **Never ships credentials** – Secrets are always read at runtime from protected environments via `load_dotenv()` and `os.getenv()` in [`prompt.py`](https://github.com/interviewstreet/hiring-agent/blob/main/prompt.py)
- **Respects external service limits** – Proactive throttling based on `X-RateLimit-Remaining` headers prevents rate limit violations
- **Reduces unnecessary network traffic** – Local caching under `cache/` maintains functionality during service outages
- **Validates and sanitizes user inputs** – Whitelist pattern matching in `extract_github_username` prevents malformed data from reaching APIs
- **Controls LLM outputs** – System prompts and client-side deduplication enforce strict selection policies

## Frequently Asked Questions

### What happens if the GitHub token is missing?

The tool operates in unauthenticated mode, falling back to the public rate limit of 60 requests per hour. As implemented in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 30‑34), the `Authorization` header is only added when `GITHUB_TOKEN` is present, allowing graceful degradation without credential errors.

### How does the hiring-agent prevent rate limit violations?

The code inspects the `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers after each API call (lines 55‑61). When remaining quota drops below 10 requests, the system calculates the wait time and sleeps proactively (lines 67‑95), ensuring the application never exceeds GitHub's rate limits.

### Is credential data ever written to log files?

No. The centralized logger abstraction from [`pdf.py`](https://github.com/interviewstreet/hiring-agent/blob/main/pdf.py) ensures that all logging statements use safe interpolation patterns. The implementation at [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) line 59 demonstrates this by logging only rate limit metadata, never exposing the `GITHUB_TOKEN` or `GEMINI_API_KEY` values.

### How does the system handle malicious GitHub URLs?

The `extract_github_username` function in [`github.py`](https://github.com/interviewstreet/hiring-agent/blob/main/github.py) (lines 16‑28) applies whitelist-based validation using multiple regex patterns. It strips whitespace, removes query strings, and only returns usernames matching valid GitHub URL patterns, preventing injection attacks and malformed API requests.