I'm testing a Java application that tries to prevent ZipSlip by simply checking whether the filename contains ".." or "./"
Since it's not a web application, I guess encoding is not an option. So, how can ZipSlip still happen in this case?
Preventing upward path traversal (by preventing the unpacking of files with a
.. element in their path) is a common and sufficient way to mitigate ZipSlip-type vulnerabilities. It obviously does need to be done on the version of the file name that the application will pass to the file system (or, if the application canonicalizes the path before passing it to the OS, on the version of the path that is combined with the target directory to produce the canonical path). Thus if there's any decoding going on that needs to happen before the check, but in most cases that doesn't apply; the file path is stored inside the zip archive, not passed directly through HTTP or whatever.
Note that this approach can cause false positives. For example, a file called "what... is that.txt" will alarm a naive check for ".." but doesn't contain it as a directory element and thus wouldn't cause upward path traversal. Similarly, a path "foo/bar/../baz.jpg" is just a safe (but sketchy) equivalent to "foo/baz.jpg" and won't cause problems (unless you're trying to prevent any subdirectories at all, which should be done by checking for the directory separator instead). On the other hand, maybe you don't care about the site not tolerating weird-but-technically-safe file paths.
./ doesn't make a lot of sense (though checking for
../ does, as that is much more likely to be an upward path traversal).
./ is simply the file system path equivalent of a no-op; it is a directory element that refers to the current directory, rather than the parent directory or any other.