Skip to content

NTPClient returns fabricated epoch timestamps before NTP synchronization (fails open, security risk) #236

@LeeLinkoff

Description

@LeeLinkoff

This was observed on an ESP32 NCU for a waveshare 8 channel relay.

NTPClient::getEpochTime() returns fabricated values before any NTP
synchronization occurs.

Minimal reproduction:

NTPClient c(udp, "pool.ntp.org", 0, 60000);
c.begin();
while (true) {
    Serial.println(c.getEpochTime());
    delay(1000);
}

Observed output immediately after boot:

14
16
17
19
...

These values are not Unix epoch timestamps. They are internal uptime
counters. No NTP server response has been received at this point.

This violates the implicit contract of getEpochTime():
"epoch" implies real UTC seconds since 1970.

The function currently has three problems:

  1. It returns non-epoch values.
  2. It does not indicate that synchronization has not occurred.
  3. Fabricated values are indistinguishable from valid data.

This behavior is unsafe for any system that uses time for:

  • authentication
  • replay protection
  • HMAC validation
  • token freshness
  • cryptographic trust

Correct behavior must be one of:

A) Return 0 or error until synchronization occurs.
B) Block until real NTP time is available.

But never return fabricated values that look valid.

The ESP32 native SNTP stack behaves correctly:
time(nullptr) remains 0 until a real NTP packet is received.

This library is safe for UI clocks and demos.
It is unsafe for security-sensitive use because it fails open with fake data.

================================================================================

Message 2 – HackerOne / public disclosure

Title: Arduino NTPClient returns fabricated epoch timestamps before NTP sync (security risk)

Description:

The Arduino NTPClient library returns fabricated "epoch" values before
any NTP synchronization occurs.

Example:

Immediately after boot:

getEpochTime() = 14
getEpochTime() = 16
getEpochTime() = 17
getEpochTime() = 19

These values are not Unix timestamps. They are internal uptime counters.
No NTP server response has been received yet.

This behavior is dangerous because:

  • The function name implies real UTC epoch time.
  • Callers receive no indication that time is invalid.
  • Fabricated values are indistinguishable from valid data.
  • Security systems may use this timestamp for:
    • authentication
    • replay protection
    • HMAC signing
    • token expiration
    • freshness validation

This creates silent authentication bypass and replay vulnerabilities
during startup or network failure.

Correct time sources must obey:

time == 0 or error → time not available
time > threshold  → real UTC, trusted

The ESP32 native SNTP stack behaves correctly:
time(nullptr) remains 0 until a real NTP packet is received.

NTPClient violates this security invariant by returning placeholder data.

This is not an NTP protocol problem.
It is a library contract violation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions