Chrono Mock has a single line of development. Security fixes are made against the
latest release and the main branch. Please confirm you can reproduce a
problem on the latest version before reporting it.
Older releases receive nothing. When a new version is published, the one before it stops being supported that day: no security updates, no backports, no patched builds. The supported version is whichever release is currently the latest, for as long as it is the latest. There is no long-term support line and none is planned, so the upgrade path for a security fix is always to move to the newest release.
Please do not open a public issue for security problems.
Use GitHub's private vulnerability reporting: open the Security tab of this repository and choose Report a vulnerability. That keeps the report private until a fix is available.
Please include:
- the version and your Windows version,
- whether you used the window (
ChronoMock.exe) or the command line (chrono.exe), - whether it was native injection or Chromium mode, and whether the target was 32-bit or 64-bit,
- a clear description and the smallest steps to reproduce, ideally one command line,
- the impact you believe it has.
You can expect an initial response within 14 days or fewer. Once a fix is ready it ships in the next release, and the advisory is published crediting the reporter unless you prefer to stay anonymous.
Chrono Mock injects a library into a program you point it at. That is the product, not a vulnerability. Everything below follows from that sentence, so it is worth reading before writing a report.
The tool loads chrono_hook.dll into the target process and rewrites what that
one process reads from the Windows time APIs. This is the same technique malware
uses, which is why antivirus software flags it, and it is why a report saying "this
program injects code into other processes" describes the feature rather than a
defect. What is in scope is the tool doing that to a process you did not choose,
or reaching further than the process you did choose.
Three properties are worth stating because a report may depend on them:
It never changes the system clock. Not in any mode, not temporarily, not as a fallback. The whole point is that the rest of the machine keeps the real time. A guard in the test suite refuses any code in this repository that sets the clock, and every guard here is pointed at code it must reject before it is trusted.
It needs no administrator rights, and asks for none. A Chrono Mock that required elevation, or acquired it, would be a different and much more dangerous tool. Note the corollary: run it elevated yourself and it can inject into elevated processes, because Windows lets a process of equal integrity do that. That is the operating system's model rather than a hole in this tool.
It makes no connections off the machine. No telemetry, no update check, nothing
downloaded while it runs. Guarded rather than promised: a test scans every Rust and
C# source in the workspace for network APIs, and the only ones it permits are listed
by file with the reason, so a new way out fails the build until somebody writes down
why it is there. The same test refuses a dependency that could speak to a network -
the tree is 51 packages and none of them can - and refuses a networking feature of
the windows crate.
A second test reads the built binaries themselves. Every Windows executable carries
an import table: the list of DLLs the loader resolves before the program runs, written
by the linker from what the code actually calls rather than from what anyone claims
about it. That test pins every module all six of our binaries link - five to seven
each - so a new one fails the build until somebody writes down why it is there. Two of
those entries are the point. The core links Winsock and nothing else that touches a
network, for the loopback debug port described below. The injected library links no
networking DLL at all, ws2_32 included, even though intercepting connect is one of
its jobs: it looks that module up only when the target has already loaded it, so the
library that ends up inside somebody else's process has nothing to reach the network
with.
Neither layer is a proof of silence, and both say so in their own headers. A module
resolved by name while the program runs is invisible to the second, which is why the
first exists, and the managed GUI is invisible to it too, which is why the first scans
C# as well. There is one loopback exception and it is deliberate:
Chromium mode does not inject at all, and instead launches the browser with
--remote-debugging-port=0 - Chromium picks a free port - reads the chosen port
from the profile that the tool created for the session, and drives the browser over
a local WebSocket. A port or profile flag supplied by the user is refused rather
than silently overridden, and the endpoint the tool connects to is checked to be
the loopback host and the port it was given. Both behaviours are covered by tests.
It cleans up after itself, and cannot clean up after the target. Chrono Mock
leaves no persistent hooks and no registry entries. It writes the session history
and a diagnostics-*.log beside itself, or under %LOCALAPPDATA%\ChronoMock\ when
its own folder is not writable, and for a Chromium target a throwaway browser
profile under %TEMP% that is deleted when the session ends and reported in the
summary when it could not be. An application run in the future writes future dates
into its own data, and no tool can undo that - the README says so before you start.
- A way to make Chrono Mock inject into a process the user did not select.
- A way for the tool to acquire privileges it was not started with.
- A way to make the audit report a channel as covered when it was not. Honest reporting is a function of this product rather than a nicety, so an audit that can be made to lie is a real vulnerability even when the substitution worked.
- A preset, calendar or session-history file that causes code execution, or that
makes the tool write outside its own folder and
%LOCALAPPDATA%\ChronoMock\. - A way to reach the Chromium mode debug port from outside the machine, or for another local process to take over a session's browser through it.
- A crash or a hook failure that corrupts the target process rather than stopping the session.
- Injecting into a program you chose. That is the product. So is loading the hook into the child processes that target spawns, which the session covers on purpose.
- Antivirus flagging the injected library. A documented false positive of the technique, explained in the README.
- Damage the application under test does to its own data when you run it at a future date, including a licence that invalidates itself on clock rollback. The README warns about this before your first session, and backing up the target's data directory is the mitigation.
- What a user with administrator rights can do on their own machine. Chrono Mock does not raise privileges, and it is not a sandbox.
- Using the tool against software you are not responsible for. That is a licensing and legal question rather than a vulnerability in this code, and it is addressed directly in the README.
The released archives carry no Authenticode signature and no published checksums. Windows will show an unknown-publisher warning, and there is at present no first-party file you can verify a download against. This is a known gap rather than an oversight, code signing is planned, and this section will be rewritten when it lands rather than quietly deleted.
Until then the honest verification path is to build from source. The project is
GPL-3.0, the injected library is chrono_hook.dll built from the code in this
repository, and the CI workflow builds both the 64-bit and 32-bit targets on every
push.
There are no repository secrets. Measured on 2026-09-07: zero. Every workflow runs on the per-job token GitHub issues for the run, and nothing else is stored here.
Access is scoped per workflow. All five workflows declare contents: read at
the top. Two jobs raise anything on top of that: the CodeQL analysis takes
security-events: write, because writing results to the Security tab is the entire
point of the job, and the single job that publishes the website takes pages: write
and id-token: write.
Every action is pinned to a commit rather than to a tag somebody else can repoint, with the release it corresponds to in a comment beside it. Dependabot updates the SHA and the comment together, so pinning does not mean freezing.
Dependencies are checked on every push. The dependency gate runs four
cargo-deny checks - licences, advisories, bans and sources - and a licence that
cannot be identified blocks the build, because for a GPL-3.0 project that ships a
binary an unidentified licence is the one answer nobody can act on. CodeQL analyses
the code on the same schedule, and secret scanning with push protection is on.
Behaviour in this repository is covered by CODE_OF_CONDUCT.md.