feat(05-02): add LEGAL.md, embed it, and wire keyhunter legal command
- Add LEGAL.md at repo root (109 lines) covering CFAA, Computer Misuse Act, EU Directive 2013/40/EU, responsible use, disclosure, and disclaimer. - Mirror to pkg/legal/LEGAL.md for go:embed (Go cannot traverse parents). - Add pkg/legal package exposing Text() for the embedded markdown. - Add cmd/legal.go registering keyhunter legal subcommand to print it.
This commit is contained in:
109
LEGAL.md
Normal file
109
LEGAL.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# KeyHunter — Legal Disclaimer for Active Key Verification
|
||||||
|
|
||||||
|
This document describes the legal considerations for using KeyHunter's active
|
||||||
|
verification feature (`keyhunter scan --verify` and related flags). Read it
|
||||||
|
carefully before enabling verification.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
KeyHunter's verification feature makes outbound HTTP calls to third-party
|
||||||
|
provider APIs (OpenAI, Anthropic, Google, Cohere, and 100+ other LLM/AI
|
||||||
|
services) in order to determine whether an API key discovered during a scan is
|
||||||
|
currently live. Verification is **opt-in**: it runs only when you explicitly
|
||||||
|
pass `--verify`. Passive scanning (the default) never contacts a third party.
|
||||||
|
|
||||||
|
## What --verify Does
|
||||||
|
|
||||||
|
- Sends a single lightweight HTTP request per discovered key to that provider's
|
||||||
|
documented verify endpoint (for example, `GET /v1/models` for OpenAI-style
|
||||||
|
APIs).
|
||||||
|
- Uses only the HTTP methods and bodies documented in the provider's public
|
||||||
|
API reference.
|
||||||
|
- Does **not** modify, create, delete, or otherwise mutate any account or data
|
||||||
|
on the provider's side.
|
||||||
|
- Reads only the metadata the provider voluntarily returns in the response
|
||||||
|
(organization name, rate limit tier, available models).
|
||||||
|
- Masks keys in all logs and output by default; the raw key is never written
|
||||||
|
to disk unless you explicitly pass `--unmask`.
|
||||||
|
|
||||||
|
## Legal Considerations
|
||||||
|
|
||||||
|
Verifying an API key that you do not own or do not have explicit permission to
|
||||||
|
test may constitute unauthorized access under computer-crime statutes in many
|
||||||
|
jurisdictions, including but not limited to:
|
||||||
|
|
||||||
|
- **United States** — Computer Fraud and Abuse Act, 18 U.S.C. § 1030 (CFAA).
|
||||||
|
Unauthorized access to a "protected computer" (broadly interpreted to
|
||||||
|
include any internet-connected server) can result in civil and criminal
|
||||||
|
liability.
|
||||||
|
- **United Kingdom** — Computer Misuse Act 1990, sections 1–3. Unauthorized
|
||||||
|
access, unauthorized access with intent, and unauthorized acts with intent
|
||||||
|
to impair are all criminal offences.
|
||||||
|
- **European Union** — Directive 2013/40/EU on attacks against information
|
||||||
|
systems, transposed into national law by each member state.
|
||||||
|
- **Provider Terms of Service** — In addition to statutory law, every provider
|
||||||
|
imposes contractual terms that typically forbid using credentials you are
|
||||||
|
not authorized to use. Violations can result in account termination and
|
||||||
|
civil claims for damages.
|
||||||
|
|
||||||
|
Making an API call with a stolen or leaked key, **even a single request that
|
||||||
|
does nothing**, may legally qualify as "access without authorization" in these
|
||||||
|
frameworks.
|
||||||
|
|
||||||
|
## Responsible Use
|
||||||
|
|
||||||
|
You should only use `--verify` in the following scenarios:
|
||||||
|
|
||||||
|
- **Your own keys** — keys that belong to accounts you personally own and
|
||||||
|
operate.
|
||||||
|
- **Authorized engagements** — penetration tests, red-team exercises, or bug
|
||||||
|
bounty programs where the scope document **explicitly authorizes** active
|
||||||
|
verification of credentials belonging to the target.
|
||||||
|
- **Your own CI/CD pipelines** — scanning your own source code, your
|
||||||
|
organization's source code (with employer authorization), or container
|
||||||
|
images you are responsible for.
|
||||||
|
|
||||||
|
Do **not** run `--verify` against keys you found in random public
|
||||||
|
repositories, pastes, or leak dumps belonging to third parties without first
|
||||||
|
obtaining the owner's consent.
|
||||||
|
|
||||||
|
## Responsible Disclosure
|
||||||
|
|
||||||
|
If you discover a leaked API key that belongs to someone else:
|
||||||
|
|
||||||
|
1. Do **not** verify it, use it, or publish it.
|
||||||
|
2. Contact the key owner directly. Look for a `security.txt` file at
|
||||||
|
`https://<domain>/.well-known/security.txt`, a security contact on their
|
||||||
|
website, or an entry in a vulnerability disclosure platform.
|
||||||
|
3. Provide enough detail for them to rotate the key (where you found it, what
|
||||||
|
provider it targets, the masked prefix) without exposing the raw secret in
|
||||||
|
your disclosure channel.
|
||||||
|
4. Give the owner reasonable time to respond and rotate before any public
|
||||||
|
disclosure.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
KeyHunter is provided "as is", without warranty of any kind, express or
|
||||||
|
implied, including but not limited to the warranties of merchantability,
|
||||||
|
fitness for a particular purpose, and non-infringement. The authors and
|
||||||
|
contributors of KeyHunter disclaim all liability for any damages, direct or
|
||||||
|
indirect, arising from the use or misuse of this tool. **You, the user, are
|
||||||
|
solely responsible** for ensuring that your use of KeyHunter complies with all
|
||||||
|
applicable laws, regulations, contracts, and terms of service in your
|
||||||
|
jurisdiction and the jurisdiction of any service you interact with.
|
||||||
|
|
||||||
|
## Consent Record
|
||||||
|
|
||||||
|
The first time you run `keyhunter scan --verify`, KeyHunter displays an
|
||||||
|
interactive consent prompt summarizing this disclaimer. You must type `yes`
|
||||||
|
(case-insensitive) to proceed. Your decision is persisted in the local SQLite
|
||||||
|
settings table under the key `verify.consent`. Granted consent is sticky
|
||||||
|
across runs; declined consent is not, so you will be re-prompted next time
|
||||||
|
(in case you change your mind or run in a different environment).
|
||||||
|
|
||||||
|
To review this document at any time, run:
|
||||||
|
|
||||||
|
keyhunter legal
|
||||||
|
|
||||||
|
To reset consent and force a re-prompt, clear the `verify.consent` setting
|
||||||
|
from your KeyHunter database.
|
||||||
17
cmd/legal.go
Normal file
17
cmd/legal.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/salvacybersec/keyhunter/pkg/legal"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var legalCmd = &cobra.Command{
|
||||||
|
Use: "legal",
|
||||||
|
Short: "Print the legal disclaimer for the --verify feature",
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
fmt.Println(legal.Text())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ func init() {
|
|||||||
rootCmd.AddCommand(scanCmd)
|
rootCmd.AddCommand(scanCmd)
|
||||||
rootCmd.AddCommand(providersCmd)
|
rootCmd.AddCommand(providersCmd)
|
||||||
rootCmd.AddCommand(configCmd)
|
rootCmd.AddCommand(configCmd)
|
||||||
|
rootCmd.AddCommand(legalCmd)
|
||||||
// Stub commands for future phases (per CLI-01 requirement of 11 commands)
|
// Stub commands for future phases (per CLI-01 requirement of 11 commands)
|
||||||
rootCmd.AddCommand(verifyCmd)
|
rootCmd.AddCommand(verifyCmd)
|
||||||
rootCmd.AddCommand(importCmd)
|
rootCmd.AddCommand(importCmd)
|
||||||
|
|||||||
109
pkg/legal/LEGAL.md
Normal file
109
pkg/legal/LEGAL.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# KeyHunter — Legal Disclaimer for Active Key Verification
|
||||||
|
|
||||||
|
This document describes the legal considerations for using KeyHunter's active
|
||||||
|
verification feature (`keyhunter scan --verify` and related flags). Read it
|
||||||
|
carefully before enabling verification.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
KeyHunter's verification feature makes outbound HTTP calls to third-party
|
||||||
|
provider APIs (OpenAI, Anthropic, Google, Cohere, and 100+ other LLM/AI
|
||||||
|
services) in order to determine whether an API key discovered during a scan is
|
||||||
|
currently live. Verification is **opt-in**: it runs only when you explicitly
|
||||||
|
pass `--verify`. Passive scanning (the default) never contacts a third party.
|
||||||
|
|
||||||
|
## What --verify Does
|
||||||
|
|
||||||
|
- Sends a single lightweight HTTP request per discovered key to that provider's
|
||||||
|
documented verify endpoint (for example, `GET /v1/models` for OpenAI-style
|
||||||
|
APIs).
|
||||||
|
- Uses only the HTTP methods and bodies documented in the provider's public
|
||||||
|
API reference.
|
||||||
|
- Does **not** modify, create, delete, or otherwise mutate any account or data
|
||||||
|
on the provider's side.
|
||||||
|
- Reads only the metadata the provider voluntarily returns in the response
|
||||||
|
(organization name, rate limit tier, available models).
|
||||||
|
- Masks keys in all logs and output by default; the raw key is never written
|
||||||
|
to disk unless you explicitly pass `--unmask`.
|
||||||
|
|
||||||
|
## Legal Considerations
|
||||||
|
|
||||||
|
Verifying an API key that you do not own or do not have explicit permission to
|
||||||
|
test may constitute unauthorized access under computer-crime statutes in many
|
||||||
|
jurisdictions, including but not limited to:
|
||||||
|
|
||||||
|
- **United States** — Computer Fraud and Abuse Act, 18 U.S.C. § 1030 (CFAA).
|
||||||
|
Unauthorized access to a "protected computer" (broadly interpreted to
|
||||||
|
include any internet-connected server) can result in civil and criminal
|
||||||
|
liability.
|
||||||
|
- **United Kingdom** — Computer Misuse Act 1990, sections 1–3. Unauthorized
|
||||||
|
access, unauthorized access with intent, and unauthorized acts with intent
|
||||||
|
to impair are all criminal offences.
|
||||||
|
- **European Union** — Directive 2013/40/EU on attacks against information
|
||||||
|
systems, transposed into national law by each member state.
|
||||||
|
- **Provider Terms of Service** — In addition to statutory law, every provider
|
||||||
|
imposes contractual terms that typically forbid using credentials you are
|
||||||
|
not authorized to use. Violations can result in account termination and
|
||||||
|
civil claims for damages.
|
||||||
|
|
||||||
|
Making an API call with a stolen or leaked key, **even a single request that
|
||||||
|
does nothing**, may legally qualify as "access without authorization" in these
|
||||||
|
frameworks.
|
||||||
|
|
||||||
|
## Responsible Use
|
||||||
|
|
||||||
|
You should only use `--verify` in the following scenarios:
|
||||||
|
|
||||||
|
- **Your own keys** — keys that belong to accounts you personally own and
|
||||||
|
operate.
|
||||||
|
- **Authorized engagements** — penetration tests, red-team exercises, or bug
|
||||||
|
bounty programs where the scope document **explicitly authorizes** active
|
||||||
|
verification of credentials belonging to the target.
|
||||||
|
- **Your own CI/CD pipelines** — scanning your own source code, your
|
||||||
|
organization's source code (with employer authorization), or container
|
||||||
|
images you are responsible for.
|
||||||
|
|
||||||
|
Do **not** run `--verify` against keys you found in random public
|
||||||
|
repositories, pastes, or leak dumps belonging to third parties without first
|
||||||
|
obtaining the owner's consent.
|
||||||
|
|
||||||
|
## Responsible Disclosure
|
||||||
|
|
||||||
|
If you discover a leaked API key that belongs to someone else:
|
||||||
|
|
||||||
|
1. Do **not** verify it, use it, or publish it.
|
||||||
|
2. Contact the key owner directly. Look for a `security.txt` file at
|
||||||
|
`https://<domain>/.well-known/security.txt`, a security contact on their
|
||||||
|
website, or an entry in a vulnerability disclosure platform.
|
||||||
|
3. Provide enough detail for them to rotate the key (where you found it, what
|
||||||
|
provider it targets, the masked prefix) without exposing the raw secret in
|
||||||
|
your disclosure channel.
|
||||||
|
4. Give the owner reasonable time to respond and rotate before any public
|
||||||
|
disclosure.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
KeyHunter is provided "as is", without warranty of any kind, express or
|
||||||
|
implied, including but not limited to the warranties of merchantability,
|
||||||
|
fitness for a particular purpose, and non-infringement. The authors and
|
||||||
|
contributors of KeyHunter disclaim all liability for any damages, direct or
|
||||||
|
indirect, arising from the use or misuse of this tool. **You, the user, are
|
||||||
|
solely responsible** for ensuring that your use of KeyHunter complies with all
|
||||||
|
applicable laws, regulations, contracts, and terms of service in your
|
||||||
|
jurisdiction and the jurisdiction of any service you interact with.
|
||||||
|
|
||||||
|
## Consent Record
|
||||||
|
|
||||||
|
The first time you run `keyhunter scan --verify`, KeyHunter displays an
|
||||||
|
interactive consent prompt summarizing this disclaimer. You must type `yes`
|
||||||
|
(case-insensitive) to proceed. Your decision is persisted in the local SQLite
|
||||||
|
settings table under the key `verify.consent`. Granted consent is sticky
|
||||||
|
across runs; declined consent is not, so you will be re-prompted next time
|
||||||
|
(in case you change your mind or run in a different environment).
|
||||||
|
|
||||||
|
To review this document at any time, run:
|
||||||
|
|
||||||
|
keyhunter legal
|
||||||
|
|
||||||
|
To reset consent and force a re-prompt, clear the `verify.consent` setting
|
||||||
|
from your KeyHunter database.
|
||||||
17
pkg/legal/legal.go
Normal file
17
pkg/legal/legal.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Package legal exposes the KeyHunter legal disclaimer as a compile-time
|
||||||
|
// embedded string.
|
||||||
|
//
|
||||||
|
// Note: Go's //go:embed directive cannot traverse parent directories, so the
|
||||||
|
// canonical LEGAL.md lives at the repo root (for user visibility) AND a
|
||||||
|
// byte-identical copy lives at pkg/legal/LEGAL.md (for embedding). This
|
||||||
|
// mirrors the dual-location pattern used in Phase 1 for provider YAML files
|
||||||
|
// (providers/*.yaml vs pkg/providers/definitions/*.yaml).
|
||||||
|
package legal
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
//go:embed LEGAL.md
|
||||||
|
var legalMarkdown string
|
||||||
|
|
||||||
|
// Text returns the embedded LEGAL.md contents.
|
||||||
|
func Text() string { return legalMarkdown }
|
||||||
22
pkg/legal/legal_test.go
Normal file
22
pkg/legal/legal_test.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package legal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestText_NonEmpty(t *testing.T) {
|
||||||
|
got := Text()
|
||||||
|
if len(got) < 500 {
|
||||||
|
t.Fatalf("Text() too short: got %d bytes, want > 500", len(got))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestText_ContainsKeyPhrases(t *testing.T) {
|
||||||
|
got := Text()
|
||||||
|
for _, phrase := range []string{"CFAA", "Responsible Use", "Disclaimer"} {
|
||||||
|
if !strings.Contains(got, phrase) {
|
||||||
|
t.Errorf("Text() missing required phrase %q", phrase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user