diff --git a/src/kernel_services/ast_queries/file.ml b/src/kernel_services/ast_queries/file.ml
index 70ef66d61040e8a0dba60b655ac82f492b051f4a..7bb60f13bd74e576c7e6f0eec94738a0bcbc9879 100644
--- a/src/kernel_services/ast_queries/file.ml
+++ b/src/kernel_services/ast_queries/file.ml
@@ -449,14 +449,7 @@ let concat_strs ?(pre="") ?(sep=" ") l =
 
 let adjust_pwd fp cpp_command =
   if Kernel.JsonCompilationDatabase.is_set () then
-    (* TODO: we currently use PWD instead of Sys.getcwd () because OCaml has
-       no function in its stdlib to resolve symbolic links (e.g. realpath)
-       for a given path. 'getcwd' always resolves them, but if the user
-       supplies a path with symbolic links, this may cause issues.
-       Instead of forcing the user to always provide resolved paths, we
-       currently choose to never resolve them.
-       We only resort to getcwd() to avoid issues when PWD does not exist. *)
-    let cwd = try Unix.getenv "PWD" with Not_found -> Sys.getcwd () in
+    let cwd = Filepath.pwd () in
     let dir =
       match Json_compilation_database.get_dir fp with
       | None -> cwd
@@ -577,10 +570,10 @@ let abort_with_detailed_pp_message f cpp_command =
     else ""
   in
   Kernel.abort
-    "failed to run: %s@\n\
+    "failed to run: %s\n(PWD: %s)@\n\
      %sSee chapter \"Preparing the Sources\" in the Frama-C user manual \
      for more details."
-    cpp_command possible_cause
+    cpp_command (Filepath.pwd ()) possible_cause
 
 let parse_cabs cpp_command = function
   | NoCPP f ->
diff --git a/src/libraries/utils/filepath.ml b/src/libraries/utils/filepath.ml
index a9741beeed61209dce74cd7f479ac2d0438113e5..c0070248e9f622d3f4a594834412f326ffa02341 100644
--- a/src/libraries/utils/filepath.ml
+++ b/src/libraries/utils/filepath.ml
@@ -323,6 +323,8 @@ type position =
 let pp_pos fmt pos =
   Format.fprintf fmt "%a:%d" Normalized.pretty pos.pos_path pos.pos_lnum
 
+let pwd () = try Unix.getenv "PWD" with Not_found -> Sys.getcwd ()
+
 (*
 Local Variables:
 compile-command: "make -C ../../.."
diff --git a/src/libraries/utils/filepath.mli b/src/libraries/utils/filepath.mli
index 4c5a6eee3c41ec7b4d319c6004a7821c529fb9b7..1f3de6c270500d72aca8b2058b5aef77a2ba48fb 100644
--- a/src/libraries/utils/filepath.mli
+++ b/src/libraries/utils/filepath.mli
@@ -207,6 +207,21 @@ type position =
 *)
 val pp_pos : Format.formatter -> position -> unit
 
+(** Return the current working directory.
+    Currently uses the environment's PWD instead of Sys.getcwd () because OCaml
+    has no function in its stdlib to resolve symbolic links (e.g. realpath)
+    for a given path. 'getcwd' always resolves them, but if the user
+    supplies a path with symbolic links, this may cause issues.
+    Instead of forcing the user to always provide resolved paths, we
+    currently choose to never resolve them.
+    We only resort to getcwd() to avoid issues when PWD does not exist.
+    Note that this function does not validate that PWD has not been tampered
+    with.
+
+    @since Frama-C+dev
+*)
+val pwd : unit -> string
+
 (*
   Local Variables:
   compile-command: "make -C ../../.."
diff --git a/src/plugins/markdown-report/sarif_gen.ml b/src/plugins/markdown-report/sarif_gen.ml
index f452170bbf5d2cc55fe973a25ec4f8ac6035e141..7378f6b6b85eaaf91cb59bc239328a692d3956a3 100644
--- a/src/plugins/markdown-report/sarif_gen.ml
+++ b/src/plugins/markdown-report/sarif_gen.ml
@@ -255,15 +255,7 @@ let gen_run remarks =
         (key, (dir :> string))
       ) (Filepath.all_symbolic_dirs ())
   in
-  (* TODO: we currently use Sys.getenv "PWD" instead of Sys.getcwd ()
-     because OCaml has no function in its stdlib to resolve symbolic links
-     (e.g. realpath) for a given path.
-     'getcwd' always resolves them, but if the user supplies a path with
-     symbolic links, this may cause issues.
-     Instead of forcing the user to always provide resolved paths, we
-     currently choose to never resolve them.
-     We only resort to getcwd() to avoid issues when PWD does not exist. *)
-  let pwd = try Sys.getenv "PWD" with Not_found -> Sys.getcwd () in
+  let pwd = Filepath.pwd () in
   let uriBases = ("PWD", pwd) :: symbolicDirs in
   let uriBasesJson =
     List.fold_left (fun acc (name, dir) ->
diff --git a/src/plugins/wp/wp_parameters.ml b/src/plugins/wp/wp_parameters.ml
index 780f7d2ff64ca948af531c0ab1bd58fbe66fe3d2..c84cfe647e4c9eb37b82379de42a7eac194477c3 100644
--- a/src/plugins/wp/wp_parameters.ml
+++ b/src/plugins/wp/wp_parameters.ml
@@ -1129,15 +1129,7 @@ let get_output_dir d =
 (* --- Session dir                                                        --- *)
 (* -------------------------------------------------------------------------- *)
 
-(* TODO: we currently use PWD instead of Sys.getcwd () because OCaml has
-   no function in its stdlib to resolve symbolic links (e.g. realpath)
-   for a given path. 'getcwd' always resolves them, but if the user
-   supplies a path with symbolic links, this may cause issues.
-   Instead of forcing the user to always provide resolved paths, we
-   currently choose to never resolve them.
-   We only resort to getcwd() to avoid issues when PWD does not exist. *)
-let default =
-  (try Sys.getenv "PWD" with Not_found -> Sys.getcwd ()) ^ "/.frama-c"
+let default = Fc_Filepath.pwd () ^ "/.frama-c"
 
 let has_session () =
   Session.is_set () ||