If you discover a security vulnerability in tsgit, please report it responsibly.
Do NOT open a public GitHub issue for security vulnerabilities.
Instead, please email the maintainers directly or use GitHub's private vulnerability reporting.
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
- Acknowledgment within 48 hours
- Assessment within 7 days
- Fix released within 30 days for critical issues
| Version | Supported |
|---|---|
| Latest | Yes |
| < Latest | No |
tsgit is a library, not a service. Trust flows from the host application down to the library; users decide what data and which adapters cross the boundary. The threat model below catalogues the protections the library applies to that boundary and the assumptions it makes about its host.
| Boundary | What crosses | Guarantee |
|---|---|---|
openRepository(opts) |
user-supplied options | every field is validated synchronously before the Repository is returned; rejection surfaces a TsgitError with code INVALID_OPTION. |
User-supplied FileSystem / HttpTransport |
adapter instances | wrapped by default with wrapFsValidator / wrapTransportValidator so every call re-validates inputs. unsafeRawAdapters: true opts out (documented as "do not use with code you do not control"). |
| Config record | RepositoryConfig |
frozen via deepFreeze at construction; subsequent mutation throws in strict mode and is silently no-op in sloppy mode. |
| Logger output | strings emitted via Logger |
wrapped by wrapLoggerSanitizer to strip ANSI escapes, redact Authorization: headers, and bound message length. |
| Progress reporter | text labels | sanitized identically to logger output before reaching the user-supplied ProgressReporter. |
| Errors | TsgitError.data |
reasons are bounded-length sanitized strings; never include raw secrets or full server responses. |
The Node and browser HTTP transports both apply a layered guard before any request leaves the process:
- Scheme allowlist — only
http:andhttps:are accepted.file:,gopher:, and arbitrary schemes are rejected withNETWORK_ERROR. - Insecure-HTTP gate — plain
http:is rejected unless the caller passesallowInsecureHttp: true(Node) orconfig.allowInsecure: true(facade). The flag is loud so a single ad-hoc lift never lingers. - Private-network blocking — hostnames that resolve to
127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,169.254.0.0/16, or the loopback IPv6 range are rejected at validation time. - DNS pinning —
clone/fetch/pushresolve the URL host once via the injectedDnsResolver(default:dns.promises.lookup), then pin the resulting IP across redirects so a server cannot smuggle a private address into a 302.
- Logger — bounded message length (1 KiB by default), Authorization header values redacted, ANSI escapes stripped. Wrapping is automatic — user-supplied loggers see only sanitized strings.
- Progress text — same sanitization as logger; user labels are bounded and stripped.
- Error
reason— every reason that flows intoTsgitError.datais truncated to 256 bytes. Server bodies, file paths, and stack frames never leak verbatim.
- Working-tree malware — tsgit does not execute hooks or
.gitattributesfilter drivers. A repo containing those will simply be ignored. - Submodule recursion — explicit opt-in only; the v1 surface does not walk submodules.
- Sparse checkout / partial clone — full clone semantics only; v2.
- Defending against a malicious adapter — users who opt into
unsafeRawAdapters: trueare on their own. The default-wrapped path is the supported surface.
Use GitHub's private vulnerability reporting (see top of file). Include
a minimal reproducer using the public openRepository surface where
possible.