Refolk
StandardProcess, data, and compliance

Repo-Derived Contact Clearance: Cleared, Restricted, or Off-Limits

Grade any email found on a code host or package registry as Cleared, Restricted, or Off-Limits, and attach the provenance record an auditor or developer will ask for.

22 min readLast reviewed October 19, 2026Read as Markdown

Key takeaways

  • A commit author email is an attribution field, not a contact listing: GitHub documents it as the way to associate commits with an account, so this standard grades it Off-Limits for any outreach.
  • GitHub's Acceptable Use Policies, Section 7, bar using information from the service, whether scraped or collected through the API, to send unsolicited emails or to sell user personal information to recruiters, headhunters, and job boards.
  • Being publicly available is not one of the GDPR Article 14(5) exceptions, so a developer in Germany or the UK must be told the source of their data at first contact, and within one month at the latest.
  • In Refolk's index, 78 of the 200 profiles with "open source maintainer" in the headline across the US, Germany, and the UK (39%) sit under GDPR or UK GDPR.
  • A contact route earns at most Restricted (one-to-one only, no sequence, no sharing) if it was found on the code host or in a package registry field, and only an owner-published, off-host contact listing can be Cleared.
  • A provenance line reading "public sources" fails an audit: every route needs the exact URL, the commit SHA or package version, a capture timestamp, and whether it came through an API or a scrape.

This standard decides what a contact route found on a code host or package registry may be used for before it reaches a CRM or an outreach sequence. It is written for recruiting-ops and rev-ops owners who answer for how data was gathered. It gives three grades, the ordered tests that assign them, the provenance record to attach to each address, and a checklist to verify the work before anything is sent.

The existing repo guides tell you whether a mined address belongs to the right person. This one assumes the match is correct and asks a different question: is that address cleared for storage, for a sequence, for sharing, or for nothing at all?

What Cleared, Restricted, and Off-Limits mean

Each grade is a set of permissions. Cleared allows CRM storage and sequenced outreach with notice. Restricted allows one-to-one contact only, with no sequence and no sharing. Off-Limits allows no outreach and no storage as a contact route.

A contact route is one address or channel plus the place it was found. The same address found in two places is two routes and can carry two grades. Always record the best-graded route you can document, not the first one you found.

GradeStore in CRMOutreach allowedSharing
ClearedYes, with provenancePersonalised, including a sequenceInternal; client disclosure triggers notice
RestrictedOwner's record onlyOne-to-one, hand-written, no automated follow-upNone: no export, no shared list, no sale
Off-LimitsSuppression entry onlyNoneNone

Three rules hold across all grades:

  • Notice is owed under every grade. Grading decides what you may do. It does not remove the duty to tell a GDPR-covered person where you got their data.
  • Off-Limits records are kept, not deleted, as suppression entries. You need to know the address exists so you don't re-import it from another source. Store the reason and nothing you would use to make contact.
  • Restricted cannot be upgraded by usage. A Restricted route that gets a reply does not become Cleared. The person replying gives you a new route (their reply address, in a conversation they chose to have), and that new route gets graded on its own.
A correctly matched address is not a cleared address. Matching answers who; clearance answers what for.

Which rules a repo-derived address has to clear

A repo-derived address has to pass four layers of rules: privacy law on notice, the platform's terms, the purpose the field states for itself, and any signal the person has given. Passing an outer layer never overrides a refusal at an inner one.

The four layers a contact route must clear

  1. Privacy law
    GDPR and UK GDPR Article 14 notice duties; US state law is not covered by this standard
  2. Platform terms
    GitHub Acceptable Use Policies Section 7; registry terms read locally
  3. Field purpose
    What the field documents itself as for: attribution, privacy, vulnerability reports
  4. Person's signal
    A noreply choice, a stated refusal, a logged objection
A route is cleared only if it passes every layer, and the innermost refusal always wins.

The platform layer: GitHub AUP Section 7

GitHub's Acceptable Use Policies have 11 numbered sections. Section 7 is "Information Usage Restrictions" and Section 8 is "Privacy". The Section 7 text reads:

"You may not use information from the Service (whether scraped, collected through our API, or obtained otherwise) for spamming purposes, including for the purposes of sending unsolicited emails to users or selling User Personal Information (as defined in the GitHub Privacy Statement), such as to recruiters, headhunters, and job boards."

Section 1 also makes users responsible for using the service in compliance with all applicable laws. Three points matter for grading:

  • The method doesn't matter. "Scraped, collected through our API, or obtained otherwise" covers a bare git clone, which exposes every author's address without touching the API. The rule doesn't try to stop collection. It controls what you do with the address afterwards.
  • Selling to recruiters is named explicitly. That is the CRM-sharing and resale path. It is why Restricted means no sharing, not just no sequence.
  • "Spamming" is contested at the one-to-one level. On a public Hacker News thread, one commenter argued that the rule bans selling API-extracted data to recruiters but does not seem to ban recruiters acquiring it themselves. That reading doesn't deal with the "sending unsolicited emails to users" clause, which covers the send itself. This standard doesn't settle the dispute in your favour. It caps on-platform routes at Restricted.

Two parts of GitHub's terms I couldn't confirm against the live page: the Section 8 wording about using information only for the purpose the user authorised, and GitHub's separate API terms. Pull the live text before you quote either in your own policy. The section number of the clause banning "excessive automated bulk activity" is also unverified.

On enforcement, a GitHub staff member replying on a Hacker News thread called scraping commit data to send unsolicited email "a clear violation of GitHub's Terms of Service". He said GitHub "can and do take action, including banning the account", and he admitted the off-platform scrape-then-spam pattern "is the hardest to police". Other users on the same thread said their spam reports were never acted on, and no named, confirmed bans have been published. Developers have raised the same complaint publicly several times over the years. In one earlier case the recruiter "admitted to following a guide online that used the API".

The law layer: GDPR Article 14

When you collect personal data from somewhere other than the person, Article 14 says you must tell them. Two content requirements matter here:

  • Article 14(2)(f): the notice must say "from which source the personal data originate, and if applicable, whether it came from publicly accessible sources".
  • Article 14(2)(b): if your legal basis is legitimate interest under Article 6(1)(f), you must state that interest.

The deadline is the earliest of three triggers:

TriggerDeadline
Data obtained1 month at most
First communicationAt that contact
Disclosure to a recipientAt first disclosure

Sources differ on emphasis. Some audit guidance lets you inform "within one month or at first contact", while other commentary stresses that whichever comes first applies. This standard takes the stricter reading.

Each route's stated purpose and default verdict

Every route documents its own purpose, and that purpose sets the ceiling on what the route can be used for. The table below shows what each source says its field is for.

RouteStated purposeSet by
Commit emailLinking commits to an accountCommitter's git config
Noreply aliasKeeping the address privateGitHub setting
Author-email (PyPI)None beyond "author's e-mail"Package metadata
Maintainer-emailMaintainer is not the original authorPackage metadata
security.txt ContactReporting vulnerabilitiesThe organisation

Two routes aren't in that table because their purpose isn't documented. I found no GitHub statement of what the profile public email is for. The npm maintainers field wasn't checked, so its purpose is unverified. Grade npm fields as Restricted at most until you've read the registry's own documentation.

Default verdicts

RouteVerdictWhy
Personal-site contact listingClearedOwner published it, off host, to be contacted
Profile email or README listingRestrictedPerson published it, but on the host (Section 7)
Package Author / Maintainer emailRestrictedNo contact purpose stated; ambiguous owner
Commit author emailOff-LimitsAttribution field, not a listing
Noreply aliasOff-LimitsNon-routable; signals a privacy choice
security.txt / SECURITY.mdOff-LimitsPurpose is vulnerability and abuse reports

Where a route was found versus what it was published for

On the code host (AUP Section 7 applies)Off the code host
On host, not for contact
Commit email, noreply alias. Off-Limits.
On host, for contact
Profile email, README listing. Restricted at most.
Off host, not for contact
Registry fields Restricted; security.txt Off-Limits.
Off host, for contact
Personal-site contact page. Cleared, with notice.
Published for another purposePublished to be contacted
Only an address its owner published off the code host for the purpose of being contacted can be Cleared.

The grading tests

Apply these tests in order. The first one that fires sets the verdict. Two reviewers who follow this order will reach the same grade, which is the whole point of writing it down.

  1. The domain is users.noreply.github.com. Off-Limits.
  2. The person is on your suppression list or has objected. Off-Limits.
  3. The route is a commit author email. Off-Limits.
  4. The route states a non-contact purpose (security.txt Contact, SECURITY.md). Off-Limits.
  5. The address is a role or list address, not a person. Off-Limits.
  6. You can't tie the address to the person through a second source (for registry fields, the project repository). Off-Limits.
  7. The address is at the corporate domain of an employer the person no longer works for. Off-Limits.
  8. The source page says it doesn't want recruiting or sales contact. Off-Limits.
  9. The route was found on the code host (profile, README) or in a registry metadata field. Restricted.
  10. The route is on the person's own off-host site and published for contact. Cleared.
  11. Nothing above fired. Off-Limits until the route is classified and the policy is amended.

What each verdict proves, and when it lies

  • Personal-site listing, Cleared. This proves the owner chose this channel for inbound contact. It lies when the "personal site" is a mirror of a README hosted on the code host, or a team page listing a shared inbox. Check who controls the domain and whether the page invites contact.
  • Profile email or README listing, Restricted. This proves the person put the address in public on purpose. It lies when the README belongs to an organisation and the address is a role inbox. Test 5 catches that. If your counsel reads Section 7 as banning any unsolicited email built on service information, move this row to Off-Limits. Make that a deliberate, written switch in your policy, not a reviewer's judgement call.
  • Package fields, Restricted. These prove someone put an address in the package metadata. They don't prove who. PEP 621 says the difference between Authors and Maintainers "is unspecified and ambiguous", and Author-email may hold several comma-separated addresses. Grade each address separately. This standard does not cover the package registry's own terms of use. Read those before you adopt this row.
  • Commit email, Off-Limits. GitHub "uses your commit email address to associate commits with your account". The address leaks because someone used git, not because they offered it to you. No condition upgrades it.

How much of a maintainer pool falls under GDPR

About two in five maintainer profiles in a three-country slice sit under GDPR-family rules, so for a large share of any developer pool, every first message has to disclose its source. In Refolk's index of professional profiles, these are the counts of profiles with "open source maintainer" in the headline:

CountryProfilesRatio to USPrivacy regime
United States1221.00US state laws
Germany470.39GDPR
United Kingdom310.25UK GDPR
DE + UK combined780.64GDPR / UK GDPR
39%
of 200 "open source maintainer" profiles across the US, Germany, and the UK sit under GDPR or UK GDPR
In Refolk's index, Germany contributes 47 and the UK 31, so the Article 14 notice is part of most European first messages, not an edge case.

Two more observations from the same index affect how you handle routes:

  • No single employer dominates. In a US sample of 25 of these profiles, the top employers each appear only once: Okta, Docker, Microsoft, AWS, CNCF, and Dynatrace. You can't build a short allow-list of "current employer" corporate domains. Test 7 has to be run person by person.
  • German maintainers cluster outside the capital. In the German sample, Karlsruhe (4) and Berlin (3) are the top regions. A search limited to Berlin misses part of the pool you need to notice-check.

US state privacy law wasn't researched for this standard. For US-only pools, the platform and field-purpose layers still apply in full, and the law layer is an open item for your counsel.

The cheapest way to apply this standard is to start the search at the Cleared route rather than mining commits and grading down. Asking Refolk for maintainers who publish a contact page on their own site returns candidates whose best route is already the one test 10 accepts.

The provenance record an auditor or complaining developer will ask for

A provenance record has to let a second reviewer reopen the exact source and see the address where it was found, without asking the sourcer. If it can't do that, it fails both an audit and the first email from a developer asking "where did you get this?"

GDPR audit guidance asks for an "inventory of all indirect data sources with categories of data received". It also warns that "'Third parties' is not specific enough. Name the type of source or, ideally, the actual source." That sets the bar at the source level. No published guidance sets field-level items such as commit SHA or capture method, so the fields below are this standard's working minimum, not a regulator's list.

Provenance record for one contact route
route_type: personal_site | profile_email | readme | registry_author | registry_maintainer | commit | noreply | security_contact
address:
verdict: cleared | restricted | off_limits
verdict_test_fired: (number of the first grading test that fired)
source_url: (exact page, file, or package release URL)
source_anchor: (commit SHA | package name and version | page capture reference)
captured_at: (ISO timestamp)
capture_method: api | scrape | manual
stated_purpose_citation: (documentation URL for this route type)
person_match_evidence: (second source tying address to person, e.g. repository link)
employment_check: (current employer and start date; commit date if commit-derived)
jurisdiction: gdpr | uk_gdpr | us | other
lia_reference: (ID of the legitimate-interest assessment for this route type)
notice_due_by: (earliest of capture + 1 month, first contact, first disclosure)
notice_sent_at:
objection: none | (date and channel)
reviewer_1:
reviewer_2:

One record per route, not per person. Use "n/a" only where the route type genuinely has no such field.

Why each of the harder fields is there:

  • source_anchor. Commit history keeps old addresses ("Any commits you made prior to changing your commit email address are still associated with your previous email address"). Without the SHA or version you can't show which address existed at which point.
  • capture_method. Section 7 names scraping and API collection alike, so this field won't protect you. It tells the auditor how the data entered your systems, and it tells you which pipelines to fix if a route type is reclassified.
  • notice_due_by. You can compute this the moment you capture the address. Store it so a report can list overdue notices before they become a complaint.

How to grade a contact route, step by step

Grading takes a sourcer a few minutes per route and an ops owner a one-time assessment per route type. The procedure runs from the cheapest exclusion to the most expensive judgement, so most bad routes are dropped in seconds.

Clearance procedure for one repo-derived contact route

  1. Classify the route
    Assign one of the six route types and attach the citation for that route's stated purpose. Done when the record shows both, in under a minute.
  2. Exclude non-routable addresses
    Match the domain users.noreply.github.com, not the prefix, and tag matches Off-Limits. Done when no noreply address remains in a contact field.
  3. Capture provenance
    Record the exact URL, the commit SHA or package version, the capture timestamp, and API or scrape. Done when a second reviewer can reopen the exact source from the record alone.
  4. Run the legitimate-interest check
    The ops owner writes down, once per route type, why outreach through that route is a legitimate interest. Done when a dated assessment is on file and referenced from each record.
  5. Grade the route against the written tests
    Apply the ordered tests; the first that fires sets the verdict. Done when two reviewers grading the same sample agree on every record.
  6. Send the notice
    Put the source notice in the first message, or send it within one month of capture if no contact comes first. Done when it names the exact source, says it was publicly accessible, and states the interest.
  7. Record objections and do-not-contact requests
    Log every objection on a suppression list that every tool checks before any send. Done when an objector cannot be re-imported or re-sequenced from any source.

The grading path for one route

  1. Domain test
    Any users.noreply.github.com address is Off-Limits immediately
  2. Route type
    Classify into one of six types and cite its stated purpose
  3. Purpose fit
    Commit and security contacts stop here as Off-Limits
  4. Person check
    Matched by a second source, current employer, not a role inbox, no objection
  5. Verdict
    Cleared or Restricted, with provenance and a notice due date
The cheapest tests run first, so most non-routable and purpose-mismatched addresses are excluded before anyone spends judgement on them.

On step 4, auditfront's Article 14 guidance says exemption reasoning should be documented "thoroughly". The same discipline applies to a legitimate-interest assessment. Write one per route type, not per person. It should cover why the outreach is in the person's reasonable expectation given where they published the address, and why a less intrusive route isn't available.

On step 5, calibrate before go-live. Have two reviewers independently grade the same sample of records, compare, and rewrite any test that produced a split. A test that two people read differently is a policy defect, not a reviewer error.

On step 6, the notice can be a short block in the first message, linked to your full privacy notice:

Source notice block for a first message (Article 14)
Where I found your details: I came across your name and this email address at {exact source URL}, which is publicly accessible. I captured them on {capture date}.

Why I am holding them: {company} has a legitimate interest in contacting you about {specific role or reason tied to your public work on X}. Your details sit in our {recruiting or sales} system and are not shared outside the team working on this.

If you would rather not hear from me, reply "no" and I will delete your contact details and add you to a do-not-contact list so you are not contacted again from any source. Full details of how {company} handles your data: {privacy notice URL}.

Paste below the personal part of the message. Replace the braces; keep the source URL exact, never "public sources".

Step 7 is yours alone. I found no do-not-contact handling procedure in GitHub's terms, so the platform gives you nothing to lean on. The suppression list has to sit upstream of every import, because the same person can reappear through a registry field or a different repo.

How repo contact clearance goes wrong

Most clearance failures are false positives: a route that looks fine to a busy sourcer but fails a test they skipped. These are the eight that matter, each with the check that catches it.

  • Treating "public" as consent. The false positive is "it's in git log, so it's fair game." Check: public availability is not an Article 14(5) exception. The notice is owed whatever the source, and commit emails fail test 3 regardless.
  • The stale commit email. Old commits keep a previous address after the person changes it, so commit history can hold several addresses per person. A corporate address from a former employer reaches the wrong mailbox, and someone else at that company reads your pitch. Check: is the commit date after the person's current employment start date? If not, test 7 fires.
  • Reading a noreply alias as reachable. Accounts created after 18 July 2017 get ID+USERNAME@users.noreply.github.com, and older aliases use a bare form on the same domain. A prefix match misses one form. Check: match on the domain, never the local part.
  • Using security.txt for recruiting. RFC 9116 makes Contact and Expires mandatory and defines Contact as "a method that researchers should use for reporting security vulnerabilities". GitHub suggests SECURITY.md as the place for "a preferred contact method for any 3rd party abuse inquiries". An address like security@ is a role, not a person. Check: grade both Off-Limits for any outreach, with no exceptions.
  • Taking Maintainer-email at face value. PyPI shows the Maintainer name linked to the first Maintainer-email, which may belong to someone else. Check: compare against the project's repository and fail test 6 if the two don't agree.
  • Calling one-to-one email "not spam". A personalised template sent one at a time is still bulk if it goes to hundreds of people. Check: count sends per template. If a Restricted route has ever been enrolled in a template that goes out at volume, that is a breach of the grade, whatever the merge fields say.
  • A vague source line. "Public sources" or "GitHub" fails an audit, and it fails the developer who asks. Check: the record holds the exact URL plus the SHA or package version.
  • Assuming the platform enforces. GitHub's own staff say off-platform scraping is hard to police, and users report unanswered spam reports. Check: never read the absence of a ban as evidence of compliance. Your provenance record and grade are the evidence.

GitHub's doxxing policy lists "personal, private email addresses", and says GitHub "will take context into account as well as whether the reported content is publicly available elsewhere". That is a takedown policy, not a usage permission. A developer who finds a commit address republished in a shared list has a platform remedy as well as a privacy-law one.

GitHub's own older documentation said it "does not get many reports of spam being sent to the email addresses in Git commits". I found no published measurement of how commit addresses split between noreply, corporate, and personal domains, so nobody knows how often test 1 or test 7 will fire on your data. Measure it on your first batch and keep the numbers.

Keeping the standard current

This standard depends on documents that change: GitHub's live policy text, registry specifications, and your own legal reading. Re-check those documents on a fixed schedule, and re-run the two-reviewer calibration whenever a test changes.

What to re-check, and how:

  • GitHub Acceptable Use Policies. Read the live page and confirm Section 7 still contains the "unsolicited emails" and "recruiters, headhunters, and job boards" wording. Pull the Section 8 text and the separate API terms, which this standard couldn't verify, and record the date you read them.
  • Registry documentation. Re-read the PyPA core metadata spec for Author-email and Maintainer-email. Read the npm documentation for its maintainers field, which wasn't checked here, before grading any npm-sourced address above Off-Limits by test 11.
  • Your Section 7 switch. Record in writing whether counsel keeps on-host routes at Restricted or moves them to Off-Limits, and who decided.
  • US law. This standard leaves the law layer open for US subjects. Close it with counsel before you treat US routes as anything other than platform-bound.
  • Calibration. After any test is added or reworded, have two reviewers re-grade a fresh sample. Ship the change only when they agree.
  • Overdue notices. Run a weekly report on notice_due_by against notice_sent_at, and delete or notify anything past due.

When a new route type appears, such as a new registry or a new metadata field, it is Off-Limits under test 11 until someone has found its documented purpose, written a legitimate-interest assessment, and added a numbered test. Refolk queries can be pointed at whichever route your policy currently clears, so the policy change and the sourcing change can ship on the same day.

Before any repo-derived route enters the CRM or a sequence

  • The record names one of the six route types and links the stated-purpose citation for that type.
  • No address on the users.noreply.github.com domain appears in any contact field.
  • No commit author email is stored in a contact field or enrolled in any sequence.
  • No security.txt Contact, SECURITY.md address, or role inbox is used for outreach.
  • The record holds the exact source URL, the commit SHA or package version, a capture timestamp, and API or scrape.
  • A second reviewer reopened the source from the record alone and reached the same verdict.
  • Registry-field addresses were matched to the person against the project repository, one address at a time.
  • Commit-derived or corporate addresses were checked against the person's current employment start date.
  • Restricted routes appear in no sequence, export, shared list, or client handoff.
  • A dated legitimate-interest assessment exists for the route type and is referenced in the record.
  • For GDPR and UK GDPR subjects, the first message names the exact source, says it was publicly accessible, and states the legitimate interest.
  • Every logged objection is on a suppression list that each sending tool checks before any send.

Questions practitioners ask

Is it legal to email developers from GitHub commits?

Under this standard, no: commit author emails are graded Off-Limits for any outreach. GitHub's Acceptable Use Policies, Section 7, bar using service information to send unsolicited emails, and a GitHub staff member publicly called scraping commit data for this a clear violation of the Terms of Service. Under GDPR, the address being public does not remove the duty to tell the person where you got it. US state law was not assessed here, so check with counsel for US-only pools.

Does GitHub's acceptable use policy ban recruiters from emailing developers?

It bans using information from the service for spamming, which it says includes sending unsolicited emails to users and selling user personal information to recruiters, headhunters, and job boards. Practitioners disagree on whether a single hand-written recruiter email counts as spamming. This standard resolves that by allowing at most Restricted use, meaning one-to-one only, for routes the person published on GitHub, and never sequences or sharing.

Can I use package maintainer emails from PyPI for outreach?

Only as Restricted, and only after you confirm the address belongs to the person you think it does. The PyPI core metadata spec defines Author-email as just the author's address with no contact purpose, PEP 621 calls the author and maintainer distinction ambiguous, and PyPI can show a maintainer name linked to someone else's address. Compare with the project repository, grade each comma-separated address separately, and read the registry's own terms locally.

How do I document provenance of sourced contact data?

Record enough that a second reviewer can reopen the exact source: the URL, the commit SHA or package version, the capture timestamp, the capture method (API or scrape), the route type, and the stated-purpose citation. GDPR audit guidance says "third parties" is not specific enough and asks you to name the actual source. No published guidance fixes a field-level list, so treat the fields in this standard as a working minimum.

Do I have to tell a developer where I found their email address?

Yes, if they are covered by GDPR or UK GDPR. Article 14 requires the notice to say where the data came from and whether it was publicly accessible, and to state the legitimate interest when that is your legal basis. The deadline is the earliest of three triggers: one month after you obtained the data, your first communication with them, or your first disclosure to another recipient, such as a client.

What should I do when a developer complains about being contacted?

Stop all outreach, add them to a suppression list that every tool checks before sending, and answer with the provenance record: the exact source URL, the capture date, and how the address was collected. If the address turns out to be a commit email or a noreply alias, it should never have been stored, so treat it as a process failure, delete it, and check which step let it through.

Try it on the search you came here for

Stop building boolean strings. Just describe the person.

Type one sentence. I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web as it is right now, and hand back a ranked list with the reason next to every name.

  1. 01Describe them

    One plain sentence. Role, city, stack, stage, whatever matters to you.

  2. 02I read the web live

    GitHub, public LinkedIn and Crunchbase records, the open web. Not a database that went stale last quarter.

  3. 03You read the shortlist

    Ranked, with the reasoning under every name. Open a profile, ask a follow-up, narrow it down.

  • No boolean, no filters, no seat to buy. One box.
  • Read at search time, so a profile updated yesterday counts today.
  • Every step visible as it runs, every name with its reason.

500 free credits on sign-up. No card, no demo call. See real searches.

Read next