HelloZeroNet/ZeroNet · error · VerifyError
Modify timestamp is in the far future!
Error message
Modify timestamp is in the far future!
What it means
verifyFile raises VerifyError('Modify timestamp is in the far future!') when the incoming content.json's 'modified' timestamp exceeds time.time() + 24 hours. ZeroNet only allows a 1-day clock skew; a timestamp further ahead would let an attacker effectively freeze the site (all later legitimate updates would be rejected as 'older').
Source
Thrown at src/Content/ContentManager.py:955
try:
if sys.version_info.major == 3 and sys.version_info.minor < 6:
new_content = json.loads(file.read().decode("utf8"))
else:
new_content = json.load(file)
except Exception as err:
raise VerifyError("Invalid json file: %s" % err)
if inner_path in self.contents:
old_content = self.contents.get(inner_path, {"modified": 0})
# Checks if its newer the ours
if old_content["modified"] == new_content["modified"] and ignore_same: # Ignore, have the same content.json
return None
elif old_content["modified"] > new_content["modified"]: # We have newer
raise VerifyError(
"We have newer (Our: %s, Sent: %s)" %
(old_content["modified"], new_content["modified"])
)
if new_content["modified"] > time.time() + 60 * 60 * 24: # Content modified in the far future (allow 1 day+)
raise VerifyError("Modify timestamp is in the far future!")
if self.isArchived(inner_path, new_content["modified"]):
if inner_path in self.site.bad_files:
del self.site.bad_files[inner_path]
raise VerifyError("This file is archived!")
# Check sign
sign = new_content.get("sign")
signs = new_content.get("signs", {})
if "sign" in new_content:
del(new_content["sign"]) # The file signed without the sign
if "signs" in new_content:
del(new_content["signs"]) # The file signed without the signs
sign_content = json.dumps(new_content, sort_keys=True) # Dump the json to string to remove whitepsace
# Fix float representation error on Android
modified = new_content["modified"]
if config.fix_float_decimals and type(modified) is float and not str(modified).endswith(".0"):
modified_fixed = "{:.6f}".format(modified).strip("0.")View on GitHub (pinned to 454c0b2e7e)
Solutions
- Fix the publishing machine's clock (enable NTP: timedatectl set-ntp true) and re-sign/re-publish with a correct timestamp
- If you are receiving this, wait until real time passes the forged timestamp or delete the bad content.json and fetch a valid one from other peers
- Check the content.json 'modified' value (date -d @<ts>) to confirm how far in the future it is
Example fix
// before (publisher with wrong clock) content["modified"] = 1900000000 // year 2030 // after import time content["modified"] = int(time.time()) // correct current timestamp before signing
Defensive patterns
Strategy: validation
Validate before calling
import json, time
content = json.load(open('content.json'))
if content.get('modified', 0) > time.time() + 60 * 60 * 24:
raise ValueError('modified timestamp more than 1 day in the future') Try / catch
from Content.ContentManager import VerifyError
try:
site.content_manager.isModified(inner_path, file)
except VerifyError as e:
if 'far future' in str(e):
fix_clock(); content['modified'] = int(time.time()); resign(content)
else:
raise Prevention
- Run NTP on every machine that signs content
- Check modified with date -d @<ts> before publishing
- Never accept content.json files with future timestamps from untrusted sources
When it happens
Trigger: isModified -> verifyFile parses a new content.json whose modified > now + 60*60*24 and passes the 'we have newer' check; typically caused by the publisher's system clock being wrong, or a malicious/malformed content.json.
Common situations: Publishing from a machine whose clock is days ahead (wrong timezone/RTC/VM clock drift); a malicious peer crafting content.json to poison the site; NTP not running on the signer's machine.
Related errors
- Includes not allowed
- Invalid json file: %s
- We have newer (Our: %s, Sent: %s)
- This file is archived!
- Invalid signers_sign!
AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02).
Data as JSON: /api/errors/eaca6f67c05366e7.
Report an issue: GitHub.