| Version | Supported |
|---|---|
main branch |
✅ |
We recommend always using the latest version of DevTrack to ensure you have all security patches.
Do not open a public GitHub issue for security vulnerabilities.
Use GitHub's private disclosure system: 👉 Report a vulnerability
This creates an encrypted private thread between you and the maintainer. Your report is never visible to the public until a fix is released.
If the advisory page is unavailable, email doshipriyanshu3@gmail.com as a fallback.
When reporting a vulnerability, please include:
- A clear description of the issue
- Steps to reproduce the vulnerability
- Potential impact
- Screenshots, logs, or proof-of-concept code (if applicable)
- Suggested remediation (optional but appreciated)
| Severity | Fix Timeline |
|---|---|
| Critical | Within 72 hours |
| High | Within 7 days |
| Medium | Within 14 days |
Acknowledgement is within 48 hours for all reports. Fix timeline is communicated within 5 business days.
- No response in 48h — Tag
@Priyanshu-byte-coderon the advisory thread - No response in 72h — Email doshipriyanshu3@gmail.com with the advisory reference
- Disagreement on severity — Request re-assessment with supporting evidence in the advisory thread
- Initial Report — Open a Security Advisory
- Acknowledgement — Maintainers respond within 48 hours
- Assessment — Issue is triaged as Critical, High, Medium, or Low severity
- Fix — A patch is developed, tested, and released per the timeline above
- Disclosure — Coordinated public disclosure after the fix is deployed via GitHub Security Advisories
Reporters are credited by name unless they request anonymity.
- Authentication bypass or session vulnerabilities
- GitHub OAuth token leakage or revocation gaps
- Cross-user data exposure via caching or shared tokens
- SQL injection or Supabase data exposure
- Server-side request forgery (SSRF) via GitHub API proxy
- Missing security headers enabling clickjacking or content injection
- Rate limit exhaustion on shared server tokens
- Issues requiring physical device access
- Social engineering
- Volumetric DoS on free-tier Vercel/Supabase infrastructure
Security fixes are treated as level:critical — the highest point tier in the GSSoC scoring system. A private advisory serves as the issue record; no public issue is required. Points are awarded on merge based on impact and fix quality.
- Report security issues privately via Security Advisories (never public issues)
- Include reproduction steps and impact assessment
- Allow maintainers reasonable time to fix before public disclosure
- Follow responsible disclosure practices
DevTrack uses Supabase with Row Level Security on all user-data tables.
| Table | RLS | Policies |
|---|---|---|
users |
✅ | SELECT, UPDATE own row only |
goals |
✅ | SELECT, INSERT, UPDATE, DELETE own rows only |
metric_snapshots |
✅ | SELECT, INSERT, DELETE own rows only |
- All RLS policies match against
auth.uid() supabaseAdmin(service role key) is server-side only, never exposed to clients- The anon key has no direct table access by default
This section is the canonical reference for what may and may not appear in logs produced by DevTrack's API and background workers. It applies to every code path that calls console.*, logger.*, pino.*, winston.*, or any third-party logging library.
The following are strictly forbidden in any log line at any level (including debug):
| Category | Examples |
|---|---|
| Authentication tokens | GitHub OAuth tokens, Supabase service-role keys, JWT bearer tokens, session cookies, refresh tokens, API keys |
| Secrets | CLIENT_SECRET, RESEND_API_KEY, DATABASE_URL containing credentials, signing keys, webhook secrets |
| Passwords | User passwords (plain or hashed), password reset tokens, MFA backup codes, TOTP seeds |
| PII | Email addresses (in URLs only — see exception below), full names, phone numbers, government IDs |
| Request/response bodies in full | Form payloads that may contain passwords, payment fields, medical info |
| Cookies and Authorization headers | Cookie:, Authorization:, Set-Cookie: values |
Exception — email addresses in URLs: the email-as-path-segment pattern (
/api/users/foo@example.com/...) is allowed in info-level request logs because the email is the path. Do not log the body of such requests, only the method and path.
| Level | Use for | Examples |
|---|---|---|
error |
Failures requiring attention | Failed to sync repo data, Rate limit hit for user ${userId} |
warn |
Recoverable issues, degraded operation | Retrying Supabase query (attempt 2/3), Cache miss for key ${nonSensitiveKey} |
info |
Lifecycle events | User ${userId} signed in via GitHub, Background sync started |
debug |
Developer-only diagnostics | Calling GitHub API: GET /user/repos (no body) |
Pattern 1: Centralised logger (preferred)
Use a single logger module that wraps the underlying library. The wrapper redacts sensitive keys before they reach the transport:
// lib/logger.ts
const REDACT_KEYS = new Set([
'authorization', 'cookie', 'set-cookie',
'password', 'token', 'secret', 'apiKey',
'accessToken', 'refreshToken', 'sessionId',
]);
function redact(value: unknown): unknown {
if (Array.isArray(value)) return value.map(redact);
if (value && typeof value === 'object') {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(value)) {
if (REDACT_KEYS.has(k)) out[k] = '[REDACTED]';
else out[k] = redact(v);
}
return out;
}
return value;
}Pattern 2: Manual redaction at the call site
When logging raw objects, copy and strip before passing to the logger:
logger.info('user.update', {
userId: user.id,
email: '[REDACTED]',
preferences: user.preferences, // safe — no PII
});- Correlation IDs — every request gets a
requestId(UUID) emitted at start and end - User identifiers —
userId(internal) or GitHublogin(public) - Resource identifiers —
repoId,goalId,metricId - Counts and durations —
cacheHits=42 durationMs=128 - Public profile fields —
login,avatarUrl,displayName(no email)
- Full request bodies
- Headers (especially
Authorization,Cookie,Set-Cookie) - Stack traces from production that include secrets in the message
- Raw SQL queries with parameter interpolation
Unit tests for the logger should assert:
- A
console.log({ authorization: '...' })call produces output whereauthorizationis[REDACTED] - Nested objects with redacted keys at depth 3+ are still redacted
- Arrays of objects with redacted keys are redacted in every element
- The original object passed to the logger is not mutated
test('redacts authorization header at any depth', () => {
const input = { req: { headers: { authorization: 'Bearer xyz' } } };
const out = redact(input) as typeof input;
expect(out.req.headers.authorization).toBe('[REDACTED]');
expect(input.req.headers.authorization).toBe('Bearer xyz'); // original intact
});When reviewing a PR that adds or modifies logging code, confirm:
- No new log call introduces a
REDACT_KEYSmember at any depth - If a new sensitive field is added to the data model,
REDACT_KEYSis updated in the same PR - Error logs include a
requestIdfor traceability - No
console.log/console.errorcalls were added (use the centralisedlogger) - No secrets or PII appear in commit messages or PR descriptions
- Client-side logging (browser console, React error boundaries) — the above applies to server-side logs only. Client logs should never include tokens because tokens should never reach the client.
- Aggregated metrics (PostHog, etc.) — governed by the privacy policy, not this document.
- Audit logs of administrative actions — these intentionally include the actor's identity and are stored separately.