diff --git a/.gitignore b/.gitignore
index 94315ebece..4681a90788 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,6 @@
 .idea
 **/.direnv
 **/.envrc
+
+# vim
+*.swp
diff --git a/src/agent/Cargo.lock b/src/agent/Cargo.lock
index 6223eb880d..444f05fd34 100644
--- a/src/agent/Cargo.lock
+++ b/src/agent/Cargo.lock
@@ -349,6 +349,12 @@ version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
 
+[[package]]
+name = "dunce"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2641c4a7c0c4101df53ea572bffdc561c146f6c2eb09e4df02bc4811e3feeb4"
+
 [[package]]
 name = "either"
 version = "1.6.0"
@@ -1208,6 +1214,7 @@ dependencies = [
  "base64",
  "bytes",
  "cpp_demangle",
+ "dunce",
  "futures",
  "hex",
  "input-tester",
diff --git a/src/agent/onefuzz/Cargo.toml b/src/agent/onefuzz/Cargo.toml
index 230a3fbc92..23e114f1e4 100644
--- a/src/agent/onefuzz/Cargo.toml
+++ b/src/agent/onefuzz/Cargo.toml
@@ -11,6 +11,7 @@ anyhow = "1.0"
 appinsights = "0.1.4"
 base64 = "0.12"
 bytes = "0.5"
+dunce = "1.0.1"
 futures = "0.3"
 hex = "0.4"
 lazy_static = "1.4"
diff --git a/src/agent/onefuzz/src/expand.rs b/src/agent/onefuzz/src/expand.rs
index 2c3fefeb93..1631ca8c7a 100644
--- a/src/agent/onefuzz/src/expand.rs
+++ b/src/agent/onefuzz/src/expand.rs
@@ -8,6 +8,7 @@ use strum::IntoEnumIterator;
 use strum_macros::EnumIter;
 
 pub enum ExpandedValue<'a> {
+    Path(String),
     Scalar(String),
     List(&'a [String]),
     Mapping(Box<dyn Fn(&Expand<'a>, &str) -> Option<ExpandedValue<'a>>>),
@@ -85,7 +86,7 @@ impl<'a> Expand<'a> {
 
     fn extract_file_name_no_ext(&self, _format_str: &str) -> Option<ExpandedValue<'a>> {
         match self.values.get(&PlaceHolder::Input.get_string()) {
-            Some(ExpandedValue::Scalar(fp)) => {
+            Some(ExpandedValue::Path(fp)) => {
                 let file = PathBuf::from(fp);
                 let stem = file.file_stem()?;
                 let name_as_str = String::from(stem.to_str()?);
@@ -97,7 +98,7 @@ impl<'a> Expand<'a> {
 
     fn extract_file_name(&self, _format_str: &str) -> Option<ExpandedValue<'a>> {
         match self.values.get(&PlaceHolder::Input.get_string()) {
-            Some(ExpandedValue::Scalar(fp)) => {
+            Some(ExpandedValue::Path(fp)) => {
                 let file = PathBuf::from(fp);
                 let name = file.file_name()?;
                 let name_as_str = String::from(name.to_str()?);
@@ -115,35 +116,35 @@ impl<'a> Expand<'a> {
     pub fn generated_inputs(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::GeneratedInputs, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::GeneratedInputs, ExpandedValue::Path(path));
         self
     }
 
     pub fn crashes(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::Crashes, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::Crashes, ExpandedValue::Path(path));
         self
     }
 
     pub fn input(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::Input, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::Input, ExpandedValue::Path(path));
         self
     }
 
     pub fn input_corpus(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::InputCorpus, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::InputCorpus, ExpandedValue::Path(path));
         self
     }
 
     pub fn generator_exe(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::GeneratorExe, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::GeneratorExe, ExpandedValue::Path(path));
         self
     }
 
@@ -155,7 +156,7 @@ impl<'a> Expand<'a> {
     pub fn target_exe(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::TargetExe, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::TargetExe, ExpandedValue::Path(path));
         self
     }
 
@@ -167,7 +168,7 @@ impl<'a> Expand<'a> {
     pub fn analyzer_exe(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::AnalyzerExe, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::AnalyzerExe, ExpandedValue::Path(path));
         self
     }
 
@@ -179,7 +180,7 @@ impl<'a> Expand<'a> {
     pub fn supervisor_exe(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::SupervisorExe, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::SupervisorExe, ExpandedValue::Path(path));
         self
     }
 
@@ -191,21 +192,21 @@ impl<'a> Expand<'a> {
     pub fn output_dir(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::OutputDir, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::OutputDir, ExpandedValue::Path(path));
         self
     }
 
     pub fn tools_dir(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::ToolsDir, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::ToolsDir, ExpandedValue::Path(path));
         self
     }
 
     pub fn runtime_dir(&mut self, arg: impl AsRef<Path>) -> &mut Self {
         let arg = arg.as_ref();
         let path = String::from(arg.to_string_lossy());
-        self.set_value(PlaceHolder::RuntimeDir, ExpandedValue::Scalar(path));
+        self.set_value(PlaceHolder::RuntimeDir, ExpandedValue::Path(path));
         self
     }
 
@@ -216,6 +217,11 @@ impl<'a> Expand<'a> {
         ev: &ExpandedValue<'a>,
     ) -> Result<String> {
         match ev {
+            ExpandedValue::Path(v) => {
+                let path = String::from(dunce::canonicalize(v)?.to_string_lossy());
+                arg = arg.replace(fmtstr, &path);
+                Ok(arg)
+            }
             ExpandedValue::Scalar(v) => {
                 arg = arg.replace(fmtstr, &v);
                 Ok(arg)
@@ -272,10 +278,16 @@ mod tests {
 
     #[test]
     fn test_expand() -> Result<()> {
-        let my_options: Vec<_> = vec!["inner", "{input_corpus}", "then", "{generated_inputs}"]
-            .iter()
-            .map(|p| p.to_string())
-            .collect();
+        let my_options: Vec<_> = vec![
+            "inner",
+            "{input_corpus}",
+            "then",
+            "{generated_inputs}",
+            "{input}",
+        ]
+        .iter()
+        .map(|p| p.to_string())
+        .collect();
 
         let my_args = vec![
             "a",
@@ -286,26 +298,46 @@ mod tests {
             "{target_options}",
             "d",
             "{input_file_name_no_ext}",
+            "{input}",
+            "{input}",
         ];
 
+        // The paths need to exist for canonicalization.
+        let input_path = "data/libfuzzer-asan-log.txt";
+        let input_corpus_dir = "data";
+        let generated_inputs_dir = "src";
+
         let result = Expand::new()
-            .input_corpus(Path::new("hi"))
-            .generated_inputs(Path::new("mom"))
+            .input_corpus(Path::new(input_corpus_dir))
+            .generated_inputs(Path::new(generated_inputs_dir))
             .target_options(&my_options)
-            .input("test_dir/test_fileName.txt")
+            .input(input_path)
             .evaluate(&my_args)?;
 
+        let input_corpus_path = dunce::canonicalize(input_corpus_dir)?;
+        let expected_input_corpus = input_corpus_path.to_string_lossy();
+        let generated_inputs_path = dunce::canonicalize(generated_inputs_dir)?;
+        let expected_generated_inputs = generated_inputs_path.to_string_lossy();
+        let input_full_path = dunce::canonicalize(input_path)?;
+        let expected_input = input_full_path.to_string_lossy();
+        let expected_options = format!(
+            "inner {} then {} {}",
+            expected_input_corpus, expected_generated_inputs, expected_input
+        );
+
         assert_eq!(
             result,
             vec![
                 "a",
-                "hi",
+                &expected_input_corpus,
                 "b",
-                "mom",
+                &expected_generated_inputs,
                 "c",
-                "inner hi then mom",
+                &expected_options,
                 "d",
-                "test_fileName"
+                "libfuzzer-asan-log",
+                &expected_input,
+                &expected_input
             ]
         );