# Story of critical security flaws I found in Glints

Four access-control flaws in Glints exposed every applicant's and recruiter's name, email, phone, and resume files via IDOR, Sequelize attribute injection, S3 resume URLs, and an unauthenticated GraphQL query.

- Payout: unconfirmed
- Severity: high
- Program: Glints
- Credited: huli
- Disclosed: 2022-02-09
- Write-up quality: 7/10
- Original: https://tech-blog.cymetrics.io/en/posts/huli/how-i-hacked-glints-and-your-resume-en/
- Library page: https://bugbountylibrary.com/r/blog%3Atech-blog-cymetrics-io-en-posts-huli-how-i-hacked-glints-and-your-resume-en
- Tags: domain:web impact:data-leak impact:pii-leak kind:bounty platform:blog sev:high tech:graphql tech:s3 technique:js-analysis technique:recon vuln:access-control vuln:idor vuln:info-disclosure

**Target:** Job platform REST APIs, RSS feed, S3 resume bucket, GraphQL endpoint
**Root cause:** Missing/incorrect access-control checks on job application, RSS feed, public profile, and GraphQL recruiter queries; Sequelize attributes param allowed leaking rssId; resumes stored at guessable S3 URLs.
**Steps:**
1. IDOR: `GET /api/recruiterats/jobApplications?where={"JobId":"<public job id>"}` returns candidate PII/resume filename
2. Enumerate JobIds from public job URLs `glints.com/tw/opportunities/jobs/.../<id>`
3. RSS IDOR: `GET https://employers.glints.com/api/feed/jobs/{RSS_ID}/approved-candidates?UserId={companyOwnerId}`
4. Leak rssId via Sequelize `attributes` param: `GET /api/companies/<id>/jobs?where={"status":"open"}&attributes=id,rssId,...`
5. Profile leak: `GET /api/publicProfiles/<userId>` returns resume filename; download `https://glints-dashboard.s3.ap-southeast-1.amazonaws.com/resume/<file>.pdf`
6. Harvest userIds via Google dork `inurl:profile/public site:glints.com`
7. GraphQL: query `findRecruiters(input:{}){id,email,role,displayName,fullName,jobTitle,jobStatus team{labels}}` on superpowered.glints.com returns all recruiter PII
**How found:** Changed JobId to another company's public job id (classic IDOR test); recognized Sequelize naming convention in query strings and guessed the `attributes` param to leak rssId; noticed resume field unfiltered in publicProfiles and guessed S3 URL pattern; subdomain recon found superpowered.glints.com and Chrome DevTools search of minified JS revealed the findRecruiters GraphQL query.
**Exploitation:** Attacker with an employer account enumerates public JobIds and queries jobApplications to dump all applicants' PII and resume filenames; resumes fetched directly from public S3. Anyone can harvest userIds via Google and pull resumes from publicProfiles. Unauthenticated GraphQL query dumps all recruiter records.
**Escalation:** Chained public job-id enumeration + IDOR to mass-exfiltrate all applicants; Google dorking scaled userId harvesting for resume downloads.
**Insight:** When an API uses Sequelize-style query strings, try injecting `attributes`/`include` to pull hidden columns like internal IDs; also check whether filtered profile APIs still leak filenames that map to predictable public S3 paths.
