Richard Zowalla created OPENNLP-1902:
----------------------------------------

             Summary:  DownloadUtil does not re-verify cached models against 
their SHA-512 checksum
                 Key: OPENNLP-1902
                 URL: https://issues.apache.org/jira/browse/OPENNLP-1902
             Project: OpenNLP
          Issue Type: Improvement
            Reporter: Richard Zowalla
             Fix For: 2.5.12, 3.0.0-M6


{\{DownloadUtil.downloadModel(URL, Class)}} verifies the SHA-512 checksum only 
on the
path where the model is actually fetched. When the model is already present in 
the
local download home, the method logs "Model file '{}' already exists. Skipping
download." and hands the file straight to the model constructor without any
integrity check:

    if (!Files.exists(localFile)) {
      ...
      Files.copy(in, localFile, StandardCopyOption.REPLACE_EXISTING);
      validateModel(url + ".sha512", localFile);   // <-- fresh download only
    } else {
      logger.debug("Model file '{}' already exists. Skipping download.", 
filename);
    }

The two entry points in this class therefore disagree: \{{existsModel(...)}} 
*does*
call \{{validateModel(...)}} for an already-present file, while 
\{{downloadModel(...)}}
— the path that actually loads the model — does not.

Consequence: once a model is in the download home (~/.opennlp by default, 
overridable
via the OPENNLP_DOWNLOAD_HOME system property), every subsequent load trusts it
unconditionally. A model that is corrupted on disk, truncated by an interrupted
download, or modified by any process with write access to that directory is 
loaded
without complaint. This is defense in depth rather than a boundary we guarantee 
—
per SECURITY.md, model files are trusted input — but the checksum is already
published and already fetched, so the check is cheap to get right.

Note the constraint on the fix: \{{validateModel(String, Path)}} downloads the
".sha512" file from the CDN each time it is called. Simply invoking it on the 
cache
path would turn every cached load into a network request and break 
offline/air-gapped
reuse of the download home, which is a large part of why the cache exists.

Proposed approach:
 - Persist the ".sha512" file alongside the model on first download.
 - On a cache hit, verify the local model against the locally stored checksum, 
with
   no network access.
 - If the stored checksum is missing (cache populated by an older version), 
either
   re-download the checksum when the network is reachable or fail closed — to be
   decided during implementation; a system property to opt out of cache 
verification
   may be warranted for constrained environments.
 - Align \{{existsModel(...)}} and \{{downloadModel(...)}} so both use the same
   verification routine.
 - Add tests: valid cached model passes; tampered cached model fails; missing
   checksum sidecar behaves as decided; no network calls on the cache-hit path.

Reported by Jeff Zemerick during review of PR #1198 (OPENNLP-1900). The current
behaviour is documented in SECURITY.md under "Downloaded models"; that note 
should be
updated when this is fixed.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to